1. 三款模型同台竞技:这个对比测试到底在测什么
先把背景交代清楚。Step 5 Preview、DeepSeek V4 Pro、GLM5.3 这三个模型放在一起做同一个 3D 游戏,本质上是一次代码生成能力的横向压力测试。为什么选 3D 游戏作为测试载体?因为 3D 游戏开发天然是一个多维度、高耦合的工程任务,它同时考验模型在图形渲染管线、场景图管理、物理碰撞检测、输入事件处理、资源加载与状态机设计等多个层面的综合能力。一个简单的 CRUD 接口生成得好,不代表模型能驾驭一个需要实时渲染循环的交互式程序。
我选择用 WorkBuddy 作为统一的开发工作台来跑这三个模型,原因也很直接:WorkBuddy 提供了标准化的项目脚手架、依赖管理和运行环境隔离,能最大程度消除环境差异对测试结果的干扰。如果每个模型都在不同的 IDE 或不同的运行时里跑,那变量就太多了,出来的结论没有参考价值。
这次测试的目标不是要分出谁“最强”——那种结论太粗糙了。我更关心的是:在同一个 3D 游戏需求下,三个模型各自会怎么拆解问题、选择什么技术栈、代码结构长什么样、运行时表现如何、遇到报错时怎么修。这些细节才是真正影响你日常开发效率的东西。
测试用的 3D 游戏需求我定得比较克制,避免过于复杂导致所有模型都翻车,也避免太简单看不出差异。核心需求如下:
- 一个 3D 场景,包含地面平面和若干立方体障碍物
- 第一人称或第三人称相机控制(WASD 移动 + 鼠标视角)
- 简单的碰撞检测(不能穿墙)
- 一个可收集的物品系统(碰到就消失并计分)
- 一个 HUD 显示当前分数和操作提示
技术栈方面,我允许模型自行选择 Web 端的 3D 方案(Three.js、Babylon.js 或原生 WebGL),但要求最终产物能在浏览器里直接跑起来。这样做的考虑是:Web 3D 的生态足够成熟,三个模型都有大量的训练数据覆盖,不会因为某个模型没见过某个冷门引擎而产生不公平的结果。
注意:测试环境的统一性至关重要。我在 WorkBuddy 里为三个模型分别创建了独立的项目空间,Node 版本锁定在 20.x,包管理器统一用 pnpm,浏览器用 Chromium 120。这些看似琐碎的细节,如果不统一,后面排查问题时你会怀疑人生。
2. 三个模型的代码生成策略对比
2.1 Step 5 Preview 的表现:结构最规整
Step 5 Preview 拿到需求后的第一反应是先规划再动手。它在 WorkBuddy 的对话窗口里先输出了一份简短的技术方案说明,大意是“我打算用 Three.js 的 ES Module 版本,通过 importmap 引入,场景用 Scene + PerspectiveCamera + WebGLRenderer 的标准三件套,碰撞检测用简单的 AABB 包围盒判断,物品收集用距离阈值触发”。
这个规划步骤看起来不起眼,但实际价值很大。它意味着模型在生成代码之前已经把架构想清楚了,后面出来的代码文件组织得相当规整:
src/ main.js -- 入口,初始化渲染器和游戏循环 scene.js -- 场景搭建,地面和障碍物 player.js -- 玩家控制器,键盘和鼠标输入 collectibles.js -- 物品生成和收集逻辑 hud.js -- HUD 更新 collision.js -- 碰撞检测工具函数每个模块职责清晰,模块间的依赖关系也处理得干净。main.js里只做初始化和主循环调度,具体逻辑都委托给各个模块。这种代码组织方式对于一个“一次性生成”的项目来说,算是相当讲究了。
Step 5 Preview 在碰撞检测上选了 AABB(轴对齐包围盒),这是最省事的方案。对于立方体障碍物和玩家胶囊体(它实际上用了一个简化的圆柱体近似)来说,AABB 够用。它没有去搞什么复杂的 GJK 算法或者物理引擎集成,这个取舍我认为是合理的——需求里没要求精确的物理模拟,能用最简单的方法解决问题就是好方法。
2.2 DeepSeek V4 Pro 的表现:代码最紧凑
DeepSeek V4 Pro 走的是另一条路。它没有先给方案,而是直接开始生成代码,但生成过程中会穿插简短的注释说明当前在做什么。最终产物是一个单文件 HTML,所有 JavaScript 代码内联在<script type="module">标签里,通过 CDN 引入 Three.js。
这个选择有它的道理:单文件意味着零配置、零构建步骤,双击 HTML 就能跑。对于快速原型验证来说,这种方式的效率是最高的。但代价是代码可读性和可维护性会差一些——所有逻辑挤在一个文件里,找起来费劲。
DeepSeek V4 Pro 在碰撞检测上用了射线投射(Raycasting)方案。它在玩家移动方向上发射一条射线,检测是否与障碍物相交,如果相交距离小于移动步长就阻止移动。这个方案比 AABB 更精确,能处理斜向移动时的碰撞,但计算量稍大。不过对于场景里只有十几个立方体的情况,性能完全不是问题。
让我比较意外的是,DeepSeek V4 Pro 在物品收集逻辑里加了一个简单的粒子效果——物品被收集时会有一圈扩散的粒子。这个细节需求里没提,是模型自己加的。虽然实现得很粗糙(就是几个小球飞散),但说明模型在“理解需求”之外还有一定的“创意补全”能力。
2.3 GLM5.3 的表现:注释最详细
GLM5.3 的代码风格介于前两者之间。它也是多文件结构,但文件划分比 Step 5 Preview 更粗一些,大概是三个文件:index.html、game.js、style.css。不过它的代码注释密度是三个模型里最高的,几乎每个函数上面都有 JSDoc 风格的注释块,参数和返回值都标注得清清楚楚。
这种风格对于学习目的来说很友好——你拿到代码后能很快理解每一段在干什么。但如果是为了快速迭代开发,过多的注释反而会显得冗余。
GLM5.3 在碰撞检测上选择了和 Step 5 Preview 类似的 AABB 方案,但实现细节有差异。它把碰撞检测封装成了一个checkCollision(position, size)函数,返回一个布尔值,调用方根据返回值决定是否回退位置。这个封装方式比 Step 5 Preview 的直接内联判断要更清晰一些。
在相机控制上,GLM5.3 默认用了第三人称跟随相机,而 Step 5 Preview 和 DeepSeek V4 Pro 都默认用了第一人称。这个差异导致 GLM5.3 的代码里多了一套相机跟随逻辑(计算相机应该位于玩家后上方某个偏移位置,并平滑插值过去)。这个选择没有对错之分,但确实影响了代码量和运行时的视觉体验。
2.4 三模型策略对比速查
| 维度 | Step 5 Preview | DeepSeek V4 Pro | GLM5.3 |
|---|---|---|---|
| 代码组织 | 多文件,模块清晰 | 单文件 HTML | 三文件,注释丰富 |
| 碰撞方案 | AABB 包围盒 | 射线投射 | AABB 封装函数 |
| 相机视角 | 第一人称 | 第一人称 | 第三人称跟随 |
| 额外创意 | 无 | 粒子收集效果 | 无 |
| 首次运行成功率 | 一次通过 | 一次通过 | 一次通过 |
| 代码行数(约) | 420 行 | 280 行 | 350 行 |
实操心得:三个模型在首次生成时都做到了“一次通过”,没有出现语法错误或明显的逻辑 bug。这说明对于 3D 游戏这种常见任务,当前主流模型的代码生成能力已经相当可靠了。真正的差异体现在代码风格、架构选择和细节处理上,而不是“能不能跑”。
3. 在 WorkBuddy 里跑通三个项目的完整流程
3.1 WorkBuddy 项目初始化与模型接入
WorkBuddy 的工作台模式是我比较喜欢的一个特性。你可以为每个模型创建一个独立的“工作区”,每个工作区有自己的文件树、终端和预览窗口。这样三个项目的依赖不会互相污染,端口也不会冲突。
具体操作流程如下:
- 打开 WorkBuddy,选择“新建工作区”,命名为
step5-3d-game - 在工作区设置里,把模型切换为 Step 5 Preview
- 在对话窗口输入完整的 3D 游戏需求描述
- 等待模型生成代码,WorkBuddy 会自动把代码文件写入工作区
- 打开内置终端,执行
pnpm install(如果模型用了 npm 包)或直接启动静态服务器 - 点击预览按钮,在 WorkBuddy 内置浏览器里查看运行效果
对 DeepSeek V4 Pro 和 GLM5.3 重复上述流程,分别创建deepseek-3d-game和glm-3d-game两个工作区。
这里有一个细节值得展开:WorkBuddy 的模型切换是在工作区级别生效的,这意味着你可以在同一个 WorkBuddy 实例里同时管理多个模型的项目,而不需要来回切换全局设置。这个设计对于做对比测试来说非常方便。
另外,WorkBuddy 的“系统缓存目录”默认在 C 盘用户目录下。如果你像我一样 C 盘空间紧张,可以在设置里把它改到 D 盘。具体路径在“设置 > 高级 > 缓存目录”里修改,改完之后建议重启一次 WorkBuddy 让配置生效。
3.2 依赖安装与运行环境配置
三个项目的依赖情况如下:
- Step 5 Preview 项目:需要
three包,通过 pnpm 安装。WorkBuddy 自动识别了package.json并提示安装。 - DeepSeek V4 Pro 项目:无本地依赖,Three.js 通过 CDN 引入。直接用一个静态服务器打开 HTML 即可。
- GLM5.3 项目:同样需要
three包,但它还额外引入了一个stats.js用于性能监控。
对于需要本地依赖的项目,在 WorkBuddy 终端里执行:
pnpm install pnpm vite devVite 会自动启动一个开发服务器,默认端口 5173。如果端口被占用,Vite 会自动切换到下一个可用端口,终端里会打印实际使用的地址。
对于 DeepSeek V4 Pro 的单文件项目,用 Python 自带的 HTTP 服务器就够了:
python -m http.server 8080然后在浏览器里访问http://localhost:8080。
注意:DeepSeek V4 Pro 的单文件项目通过 CDN 加载 Three.js,这意味着运行时需要联网。如果你在离线环境下测试,需要把 Three.js 的 CDN 文件下载到本地并修改引用路径。Step 5 Preview 和 GLM5.3 的项目因为用了本地 npm 包,离线也能跑。
3.3 首次运行的实际表现记录
三个项目首次运行的结果:
Step 5 Preview:页面加载后场景正常渲染,地面是灰色的,障碍物是随机分布的蓝色立方体,玩家可以用 WASD 移动,鼠标拖拽旋转视角。物品是黄色的旋转小方块,碰到后消失,HUD 分数从 0 变成 1。一切正常,没有控制台报错。
DeepSeek V4 Pro:场景渲染正常,但障碍物是红色的,物品是绿色的。移动和碰撞都正常。收集物品时有粒子效果,视觉上比另外两个项目更丰富一些。控制台无报错。
GLM5.3:场景渲染正常,但因为用了第三人称相机,初始视角是从玩家后上方往下看。移动时相机平滑跟随,手感不错。但有一个小问题:当玩家靠近场景边缘时,相机会穿到地面以下,导致画面短暂变黑。这是一个相机碰撞检测缺失的问题,后面会详细说怎么修。
三个项目在功能层面都达到了需求的基本要求,差异主要体现在视觉风格和操作手感上。Step 5 Preview 最“标准”,DeepSeek V4 Pro 最“花哨”,GLM5.3 最“舒适但有小瑕疵”。
4. 踩坑记录与修复方案
4.1 GLM5.3 相机穿地问题的修复
前面提到 GLM5.3 的第三人称相机在玩家靠近场景边缘时会穿到地面以下。这个问题的根因是:相机跟随逻辑只计算了“玩家位置 + 偏移量”,没有检测相机与地面之间是否有遮挡。
修复思路很简单:在每帧更新相机位置后,加一个射线检测,从玩家位置向相机位置发射射线,如果射线与地面相交,就把相机位置调整到交点上方一点点。
在 GLM5.3 生成的代码里,相机更新逻辑大概长这样:
// 修复前的代码 const cameraOffset = new THREE.Vector3(0, 5, -8); camera.position.copy(player.position).add(cameraOffset); camera.lookAt(player.position);修复后的代码:
// 修复后的代码 const cameraOffset = new THREE.Vector3(0, 5, -8); const desiredPosition = player.position.clone().add(cameraOffset); // 从玩家向期望相机位置发射射线 const direction = desiredPosition.clone().sub(player.position).normalize(); const distance = desiredPosition.distanceTo(player.position); const raycaster = new THREE.Raycaster(player.position, direction, 0, distance); const intersects = raycaster.intersectObjects(groundObjects); if (intersects.length > 0) { // 相机被地面遮挡,把相机拉到交点前方 const safeDistance = intersects[0].distance - 0.5; camera.position.copy(player.position).add(direction.multiplyScalar(safeDistance)); } else { camera.position.copy(desiredPosition); } camera.lookAt(player.position);这个修复方案的核心思路是“相机不能跑到遮挡物后面”。0.5 的偏移量是为了避免相机贴在地面上导致近裁剪面穿模。实测下来这个修复很稳,相机再也没穿过地面。
4.2 DeepSeek V4 Pro 粒子效果的显存泄漏
DeepSeek V4 Pro 的粒子效果虽然好看,但有一个隐患:每次收集物品时都会创建新的粒子几何体和材质,但收集完成后没有销毁。如果玩家收集了大量物品,这些废弃的几何体会堆积在显存里,最终导致页面卡顿甚至崩溃。
修复方法是在粒子动画结束后调用dispose():
// 粒子动画完成后清理 function cleanupParticles(particleSystem) { particleSystem.geometry.dispose(); particleSystem.material.dispose(); scene.remove(particleSystem); }在动画循环里加一个计时器,粒子存活时间超过 1 秒就调用这个清理函数。这个坑其实很典型——任何动态创建和销毁的 3D 对象都需要手动管理生命周期,JavaScript 的垃圾回收管不到 GPU 显存。
4.3 Step 5 Preview 的输入延迟问题
Step 5 Preview 的项目在首次运行时,键盘输入有一个约 100 毫秒的延迟感。排查后发现原因是:它在每一帧的requestAnimationFrame回调里直接读取键盘状态,但键盘事件监听器用的是keydown和keyup的默认行为,没有调用preventDefault()。在某些浏览器里,这会导致按键事件被浏览器的默认滚动行为干扰。
修复很简单,在键盘事件处理函数里加上event.preventDefault():
window.addEventListener('keydown', (event) => { event.preventDefault(); keys[event.code] = true; });加上之后输入延迟明显降低,移动变得跟手了。这个坑不算大,但如果你不熟悉浏览器事件模型,可能会排查很久。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 修复方案 |
|---|---|---|---|
| 页面白屏,控制台报 404 | Three.js 路径错误 | 检查 importmap 或 CDN 地址 | 修正路径或改用本地包 |
| 模型加载后不可见 | 相机位置或朝向错误 | 打印相机 position 和 lookAt | 调整相机初始位置 |
| 移动时穿墙 | 碰撞检测未生效 | 在碰撞判断处打日志 | 检查碰撞函数调用时机 |
| 帧率逐渐下降 | 对象未销毁导致显存泄漏 | 用 Performance 面板看内存曲线 | 手动 dispose 废弃对象 |
| 键盘输入无响应 | 事件监听器未绑定或 preventDefault 缺失 | 在监听器里打日志 | 补上 preventDefault |
| 相机穿模 | 缺少相机碰撞检测 | 观察相机与场景物体的相对位置 | 加射线检测限制相机距离 |
实操心得:3D 游戏开发里,90% 的“诡异 bug”都可以归结为三类——坐标系搞错了、生命周期没管理好、事件绑定时机不对。遇到问题时先往这三个方向想,能省很多时间。
5. 三个模型的适用场景与选择建议
5.1 什么情况下选 Step 5 Preview
Step 5 Preview 的代码结构最规整,模块划分最清晰。如果你需要的是一个可以继续迭代和扩展的项目基底,它是最合适的选择。它的代码风格接近一个有条理的工程师写出来的东西,变量命名规范,函数职责单一,没有太多“炫技”的成分。
具体来说,以下场景优先考虑 Step 5 Preview:
- 你要在这个 3D 游戏基础上继续加功能(比如加敌人 AI、加关卡系统)
- 你需要把代码交给团队其他人维护
- 你希望代码本身有教学价值,能用来学习 3D 游戏架构
它的不足在于视觉表现比较朴素,没有额外的视觉效果。但这不是缺点,只是定位不同。
5.2 什么情况下选 DeepSeek V4 Pro
DeepSeek V4 Pro 的优势是快速出效果。单文件、零配置、打开就能跑,而且自带粒子效果这种“加分项”。如果你只是想快速验证一个 3D 交互的想法,或者做一个 demo 给别人看,它的效率是最高的。
适合的场景:
- 快速原型验证,不需要长期维护
- 做演示或教学示例,需要单文件方便分发
- 对视觉效果有一定要求,但不想自己写特效代码
但要注意它的显存管理问题,如果收集物品的逻辑会被频繁触发,记得加上清理代码。
5.3 什么情况下选 GLM5.3
GLM5.3 的第三人称相机和详细注释是它的两个特色。第三人称相机对于某些类型的游戏(比如平台跳跃、角色扮演)来说比第一人称更合适。详细注释则让代码更容易理解。
适合的场景:
- 你需要第三人称视角的游戏
- 你希望代码有详细注释,方便自己或他人阅读
- 你对相机跟随的平滑度有要求
但它的相机穿地问题需要修复,这个修复不复杂,但如果你不熟悉 Three.js 的射线检测 API,可能需要查一下文档。
5.4 三模型综合评分
| 评分维度 | Step 5 Preview | DeepSeek V4 Pro | GLM5.3 |
|---|---|---|---|
| 代码可维护性 | 9/10 | 6/10 | 8/10 |
| 首次运行稳定性 | 10/10 | 9/10 | 8/10 |
| 视觉表现力 | 7/10 | 9/10 | 7/10 |
| 学习友好度 | 8/10 | 6/10 | 9/10 |
| 扩展灵活性 | 9/10 | 6/10 | 8/10 |
| 开箱即用速度 | 8/10 | 10/10 | 8/10 |
这张表不是要给出一个“谁最好”的结论,而是帮你根据自己的需求快速定位。如果你追求稳定和可维护,选 Step 5 Preview;如果你追求速度和效果,选 DeepSeek V4 Pro;如果你需要第三人称和详细注释,选 GLM5.3。
6. 用 WorkBuddy 做多模型对比测试的几条经验规则
6.1 给 WorkBuddy 定几条全局规则
在 WorkBuddy 里做多模型对比测试时,我建议在“自定义指令”里预设几条全局规则,这样每个新工作区都会自动应用,不用每次手动配置。我常用的规则如下:
- 所有项目统一使用 pnpm 作为包管理器
- 所有项目统一使用 Vite 作为开发服务器
- 代码文件统一放在
src/目录下 - 禁止使用任何需要全局安装的 CLI 工具
- 生成的代码必须包含中文注释
这几条规则看起来简单,但能大幅减少环境差异带来的干扰。特别是“统一使用 pnpm”这条,如果你不锁定包管理器,有的模型会用 npm,有的会用 yarn,node_modules的结构不一样,排查问题时很烦。
6.2 跨对话记忆的利用
WorkBuddy 有一个“跨对话记忆”的 skill,可以在不同对话之间保持上下文。做对比测试时,我会把三个模型的测试结果都记录在同一个对话线程里,这样当我问“刚才 GLM5.3 的相机问题是怎么修的”时,WorkBuddy 能直接引用之前的对话内容,不需要我重新描述。
这个功能对于长期跟踪多个项目的场景特别有用。你不需要自己维护一个外部文档来记录每个项目的状态,WorkBuddy 会帮你记住。
6.3 缓存目录迁移到 D 盘
前面提过 WorkBuddy 的默认缓存目录在 C 盘。如果你同时跑多个 3D 项目,node_modules和构建缓存会迅速吃掉几个 GB 的 C 盘空间。把缓存目录改到 D 盘是一个很实际的优化。
操作路径:设置 > 高级 > 缓存目录 > 选择 D 盘下的某个文件夹。改完之后,已有的缓存不会自动迁移,你需要手动把旧缓存目录里的内容复制过去,或者直接删掉旧缓存让 WorkBuddy 重新生成。
注意:迁移缓存目录后,第一次启动项目时依赖需要重新安装,因为
node_modules的路径变了。这不是 bug,是预期行为。
6.4 安全审核与私有化部署的考量
WorkBuddy 内置了安全审核机制,会对模型生成的代码进行静态扫描,检测是否有明显的安全风险(比如硬编码密钥、不安全的 eval 调用等)。在做 3D 游戏这种项目时,安全审核通常不会拦截什么,但如果你生成的代码里包含了网络请求或文件读写操作,审核可能会提示你确认。
如果你在企业环境下使用 WorkBuddy,它还支持私有化部署。私有化部署的意义在于代码和数据不出内网,对于有合规要求的团队来说这是刚需。部署方式一般是 Docker 镜像,具体步骤参考官方文档就行,这里不展开。
7. 从这次测试里提炼出的可复用方法
7.1 如何设计一个有效的模型对比测试
这次测试让我总结出一个可复用的对比测试方法论,核心原则是控制变量、聚焦差异、记录过程。
控制变量方面,我锁定了运行时版本、包管理器、浏览器版本、项目结构规范。这些如果不统一,你很难判断一个模型的失败是因为它本身能力不行,还是因为环境配置有问题。
聚焦差异方面,我没有去测“哪个模型能生成更复杂的游戏”,而是把需求控制在中等复杂度,然后观察三个模型在相同需求下的不同选择。这些选择差异才是最有信息量的部分。
记录过程方面,我把每个模型的生成时间、首次运行结果、遇到的报错、修复方案都记录下来了。这些记录在写这篇总结时直接变成了素材,不需要事后回忆。
7.2 3D 游戏项目的最小可行架构
从三个模型的生成结果里,我提炼出一个 3D 游戏项目的最小可行架构,你可以直接拿去用:
project/ index.html -- 入口页面,包含 canvas 和 importmap src/ main.js -- 初始化渲染器、场景、相机,启动主循环 scene.js -- 地面、障碍物、光照 player.js -- 玩家控制器(键盘 + 鼠标) collision.js -- 碰撞检测工具函数 collectibles.js -- 物品生成、旋转动画、收集判定 hud.js -- 分数显示和操作提示 package.json -- 依赖声明 vite.config.js -- 开发服务器配置这个架构的好处是每个模块的职责边界清晰,你可以单独替换某个模块而不影响其他部分。比如你想把第一人称相机换成第三人称,只需要改player.js里的相机逻辑,其他文件不用动。
7.3 模型生成代码的验收清单
拿到模型生成的 3D 游戏代码后,我建议按以下清单逐项验收:
- 能跑起来:页面加载后场景正常渲染,无控制台报错
- 输入响应正常:键盘和鼠标操作都能正确触发
- 碰撞检测有效:玩家不能穿过障碍物
- 游戏循环稳定:帧率稳定在 60fps 左右,没有明显卡顿
- 资源管理正确:动态创建的对象在不需要时被销毁
- 代码可读:变量命名合理,关键逻辑有注释
- 边界情况处理:玩家移动到场景边缘时不会出现异常
这七条里,前四条是硬性要求,后三条是加分项。如果前四条有问题,这个代码就不能用;后三条有问题,可以自己修。
7.4 后续可以扩展的方向
如果你已经跑通了基础版本,想继续深入,可以考虑以下扩展方向:
- 加入物理引擎:用 cannon-es 或 rapier 替换手写的碰撞检测,支持更复杂的物理交互
- 加入音效系统:用 Howler.js 或 Web Audio API 添加背景音乐和音效
- 加入关卡系统:用 JSON 定义关卡布局,动态生成场景
- 加入敌人 AI:用简单的状态机实现巡逻、追击、攻击行为
- 加入存档系统:用 localStorage 保存玩家进度
这些扩展方向每一个都可以单独作为一个测试任务,用来进一步对比三个模型的能力边界。
8. 一些零散但有用的实操细节
8.1 Three.js 的 importmap 配置
Step 5 Preview 和 GLM5.3 都用了 importmap 来引入 Three.js。这个配置如果写错了,页面会直接白屏。正确的写法如下:
<script type="importmap"> { "imports": { "three": "https://unpkg.com/three@0.160.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/" } } </script>注意three/addons/后面的斜杠不能少,否则子路径导入会失败。这个坑我踩过,排查了半小时才发现是少了一个斜杠。
8.2 鼠标视角控制的实现要点
第一人称视角的鼠标控制,核心是监听mousemove事件,根据鼠标移动量更新相机的欧拉角。关键代码如下:
let yaw = 0; let pitch = 0; document.addEventListener('mousemove', (event) => { if (document.pointerLockElement) { yaw -= event.movementX * 0.002; pitch -= event.movementY * 0.002; pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch)); camera.rotation.set(pitch, yaw, 0, 'YXZ'); } });pitch需要限制在正负 90 度之间,否则相机会翻转。camera.rotation的第四个参数'YXZ'表示旋转顺序,这个顺序对于第一人称相机来说是正确的。
8.3 物品收集的距离判定
物品收集的判定逻辑很简单:每帧计算玩家与物品之间的距离,如果小于某个阈值就触发收集。关键代码如下:
const collectDistance = 1.5; collectibles.forEach((item, index) => { const distance = player.position.distanceTo(item.position); if (distance < collectDistance) { scene.remove(item); collectibles.splice(index, 1); score += 1; updateHUD(); } });阈值1.5是一个经验值,太小了玩家要贴得很近才能收集,太大了又显得不精确。你可以根据玩家移动速度和物品大小调整这个值。
8.4 帧率稳定的关键:避免在循环里创建对象
3D 游戏卡顿的一个常见原因是:在requestAnimationFrame回调里频繁创建新对象(比如new THREE.Vector3())。每次创建都会触发垃圾回收,垃圾回收会暂停主线程,导致帧率波动。
正确的做法是在循环外面预先创建好临时对象,循环里复用:
// 不好的做法 function animate() { const direction = new THREE.Vector3(); // 每帧都创建 // ... } // 好的做法 const tempDirection = new THREE.Vector3(); // 只创建一次 function animate() { tempDirection.set(0, 0, 0); // 复用 // ... }这个优化对于简单场景可能看不出差别,但如果场景里有几百个物体,帧率差异会非常明显。
8.5 WorkBuddy 终端的使用技巧
WorkBuddy 内置终端支持多标签页,你可以为每个项目开一个标签页,分别运行各自的开发服务器。切换标签页就能切换项目,不需要反复cd到不同目录。
另外,WorkBuddy 终端支持命令历史搜索(Ctrl+R),这个功能在调试时很有用。比如你之前跑过一个复杂的构建命令,忘了具体参数,按 Ctrl+R 输入关键词就能找回来。
实操心得:在 WorkBuddy 里做多项目对比时,给每个终端标签页重命名(右键标签页 > 重命名),标上项目名和模型名。这样一眼就能看出哪个终端在跑哪个项目,不会搞混。
9. 关于模型选择的一点个人看法
跑完这轮测试,我最大的感受是:当前主流模型在 3D 游戏代码生成这个任务上,差距没有想象中那么大。三个模型都能一次生成可运行的代码,核心功能都实现了,差异主要体现在代码风格和细节处理上。
这意味着什么呢?意味着你在选择模型时,不应该只看“哪个模型更强”这种笼统的结论,而应该看哪个模型的输出风格更符合你的工作习惯。如果你喜欢结构清晰的模块化代码,Step 5 Preview 更合适;如果你喜欢快速出效果,DeepSeek V4 Pro 更合适;如果你需要详细注释和第三人称视角,GLM5.3 更合适。
另一个感受是:模型生成的代码永远需要人工审查和修复。三个模型都或多或少有一些小问题(相机穿地、显存泄漏、输入延迟),这些问题不修也能跑,但修了之后体验会好很多。把模型当成一个“能快速写出 80 分代码的助手”,而不是“能写出 100 分代码的专家”,这个心态比较实际。
最后说一个我自己的习惯:每次用模型生成代码后,我都会花几分钟通读一遍关键逻辑,特别是涉及资源管理和事件处理的部分。这几分钟的投入,往往能帮你提前发现那些“跑一会儿才暴露”的问题。模型不会替你思考,它只是帮你把思考的起点往前挪了一大步。