最近拿到一个新模型的抢先体验资格——Step 5 Preview。名字挺低调,宣传口径里特意强调了对代码生成和复杂场景渲染的强化。作为一个平时喜欢折腾AI写小游戏的人,我第一反应不是跑benchmark,而是拉上现在呼声很高的DeepSeek V4 Pro和GLM5.3,用一模一样的题目做一次同题实操。题目就一个:在浏览器里做一个能玩的3D迷宫跑酷游戏。
这篇文章没有任何跑分表倾向,就是纯粹的实测记录。我会把三个模型生成的第一轮代码、跑起来之后的效果、后续修复问题的过程,以及我在这个过程中踩到的坑全部摊开讲。适合谁看?想用AI写3D交互原型的人,正在纠结选哪个模型做前端小项目的人,还有纯粹想看AI写代码到底靠不靠谱的好奇选手。如果你只打算复制粘贴代码,不想理解原理,也可以直接跳到第三章拿现成方案。
先说结论:Step 5 Preview这次确实给了一点惊喜,DeepSeek V4 Pro和GLM5.3也都不是吃素的,但三者暴露的问题非常有代表性。下面进入正题。
1. 评测前的三个关键决策:游戏选型、评分维度和提示词设计
1.1 为什么选"3D迷宫跑酷"而不是热门大世界
选游戏题是有讲究的。太简单的比如"生成一个旋转立方体",三个模型都是秒过,看不出差距。太复杂的比如"开放世界MMO",没有一个模型能在单轮对话里完成,后面全得靠人工补,失去了对比意义。
3D迷宫跑酷是个很好的中间档:它必须有三维场景搭建、相机跟随、碰撞检测、玩家输入、动态目标刷新、计分UI。这些元素几乎覆盖了3D游戏开发里的日常核心需求,同时单文件HTML能承载完整逻辑,不需要引入复杂构建工具。而且迷宫这个主题对美术要求极低,用BoxGeometry和MeshLambertMaterial就能搭出来,模型不需要画贴图、写骨骼动画,降低了"能否跑起来"和"美术是否好看"之间的耦合。我的诉求很明确:让AI把有限的计算能力全部花在逻辑正确性上,别浪费在生成一堆永远不会被看到的方砖纹理上。
1.2 评分维度不只看"能跑",还要看"改得起"
很多AI写代码的评测只看"第一轮生成代码能不能运行",这其实是个陷阱。稍微复杂一点的项目,第一轮能跑的代码大概率逻辑是残缺的,真正考验模型的是第二轮、第三轮修复的质量。所以我的评分维度分成五档:
| 维度 | 权重 | 说明 |
|---|---|---|
| 首轮可运行率 | 20% | 生成代码粘贴到浏览器后能否直接渲染出场景,是否存在致命语法错误 |
| 渲染正确性 | 20% | 迷宫规模、墙体位置、相机视角、光源是否合理,是否存在大片黑屏或视线穿透 |
| 交互流畅度 | 20% | WASD移动、跳跃、碰撞反应是否跟手,会不会穿墙、漂移、卡死 |
| 代码可读性 | 15% | 变量命名是否清晰,是否有注释,逻辑块是否分离,这决定了后续AI修复的难度 |
| 二次修复效率 | 25% | 我抛出同一个bug描述,模型能否准确找到问题并用最小改动解决 |
这个评分体系没有把"生成速度"放进去,因为实际体感三个模型差距基本在几秒内,感知不强。真正影响体验的是二次修复时AI能否理解自己之前生成的代码,这也是为什么可读性占据一定比重。
1.3 提示词固定死,才算公平
我用了完全相同的提示词,一个字都没改发给三个模型,原文是:
请生成一个完整的 HTML 文件,使用 Three.js 实现一个 3D 迷宫跑酷游戏。要求:
- 迷宫墙体为长方体,墙高 2 单位,厚度 1 单位,迷宫里至少 12 面墙,布局不重复。
- 玩家角色用绿色立方体表示,大小为 0.8 单位,通过 WASD 控制移动,空格键跳跃。
- 目标宝石用黄色八面体表示,随机刷新在迷宫地面空闲位置,玩家触碰后得分加 10,并立即在另一个随机位置刷新。
- 使用第三人称相机:相机始终跟随玩家,从后方 45 度角观察,距离 6 单位。
- 碰撞检测使用 AABB 轴对齐包围盒,墙体为静态障碍物,玩家不能穿墙。
- 游戏区域尺寸 30 x 30 单位,地面为浅灰色网格纹理。
- 页面左上角显示当前得分,右上角显示操作提示。
- 所有代码放到一个 HTML 文件中,使用 CDN 加载 Three.js r160 版本。
为什么要用 CDN 加载而不是本地依赖?因为这样模型生成的代码在浏览器里直接开就能跑,不需要先安装 npm 包,降低评测环境差异。我还在提示词里明确写了"墙体布局不重复",避免所有模型都生成一个四四方方的网格——虽然事后证明这个约束对某个模型来说还是太容易被忽略。
2. 三份代码的生成结果与架构拆解
2.1 Step 5 Preview:几乎一次跑通,代码结构接近"生产级"
先说意外惊喜的 Step 5 Preview。第一轮生成的HTML大约420行,没有用任何额外的依赖,除了Three.js本体。它没有把逻辑揉在一个大函数里,而是拆成了initScene、createWalls、createPlayer、createGem、updatePlayer、checkCollision这样几个函数。每个函数上方还有中文注释,解释了参数含义。
最让我意外的是碰撞检测的实现。其他模型大多把碰撞检测写成"玩家即将移动到的位置是否落在墙体的包围盒内",这会导致高速移动时卡顿或者穿模。Step 5 Preview的做法是先计算出下一步的位置,然后沿着X轴和Z轴分别做检测,再分别修正坐标。也就是说,它把轴向速度拆开处理,避免了斜向移动时在墙角被卡死的问题。这一段代码虽然不复杂,但能看出模型理解了一个关键物理常识:轴分离的碰撞修正比整体包围盒判定更适合第一人称跑酷。
它还加入了一个我提示词里没明确要求的小设计:宝石刷新时,会先检测生成点是否在墙体内或距离墙体小于1个单位,如果条件不满足就重新随机。这个细节让"随机刷新"真正变得可用,否则宝石很容易卡在墙中间。这个细节我在第二轮之前都没有意识到,算是意外收获。
当然它也有问题:首轮生成的代码里,跳跃高度只有1.2单位,而墙体高度是2单位,也就是说玩家永远跳不上墙顶——这本来是合理的,因为迷宫游戏玩家不需要跳上墙。但空格跳跃这个动作就变得纯粹是动画效果,没有实际功能。我第一轮没太在意,因为游戏本来也不设计跳墙玩法。后面再说这个点。
2.2 DeepSeek V4 Pro:跑得动但小坑不少
DeepSeek V4 Pro首轮生成的代码也能跑,而且得分刷新逻辑是正确的。但它有几个让我印象深刻的坑。
最明显的是相机跟随。它确实是第三人称相机,距离也设置到了6单位,但它把相机直接固定在玩家角色的正后方,没有做角度偏移。玩家向后走的时候,相机会严格跟着玩家转向,导致视角在后退时会突然翻转。实际体验就是,你按着S键后退,整个画面会快速旋转180度,极易头晕。这个问题根因在于它直接复制了玩家对象的旋转角度到相机上,相当于把相机绑死到了玩家身上。正常情况下,相机应该保持一个世界方向的偏移量,只在玩家改变朝向时做平滑插值。
另一个问题是碰撞响应过冲。当玩家以速度5单位/秒撞向墙体时,Step 5 Preview会把玩家位置精确修正到墙体的边缘,而DeepSeek V4 Pro的修正逻辑是先把玩家位置降低一个速度增量,再尝试重新移动。在高帧率下表现尚可,但如果帧率掉到30以下,碰撞后玩家会被弹开半米多,感觉像是被墙踢了一脚。这个问题后来我反馈给模型,它给出的修复方案还算靠谱,把修正逻辑改成了以AABB半宽为基础进行钳位。
第三,代码可读性一般。DeepSeek V4 Pro生成的代码大量使用了三元表达式和嵌套函数,变量名非常精简,比如w代表墙,g代表宝石,p代表玩家。在首轮生成时这没什么,但当我让它"把跳跃改成按两次空格二段跳"时,它明显需要更多时间去理解自己写的这些简写变量。这是我评分维度里可读性占比15%的原因——模型写代码给自己看没问题,但AI迭代维护的时候,可读性直接决定了修改效率。
2.3 GLM5.3:逻辑严谨但过度设计
GLM5.3生成的代码是三种里结构最"工程化"的。它主动引入了类继承结构:一个Entity基类,Player和Gem继承自它;一个CollisionManager类专门管理碰撞;一个GameController类负责游戏主循环。如果这是在写一个大型多人游戏项目,我会觉得这个架构很合理。但在这道题面前,这种设计有点过度了——整个游戏就一个HTML文件,结果超了600行,其中至少有150行是类之间的事件绑定和构造函数参数传递。
更重要的是,GLM5.3的首轮代码在浏览器里无法直接运行。它默认使用了ES Module语法,也就是import * as THREE from 'three',同时要求Three.js以模块方式加载。我在提示词里明确说了用CDN加载r160版本,默认是非模块方式,结果GLM5.3生成的HTML里写的是<script type="module">,并引用了https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js。这本身没问题,问题是它没有把同目录下的其他依赖处理好,局部报错导致整个场景白屏。
实际上这也给了我一个经验:如果要在本地直接用file://协议打开HTML,非模块的Three.js代码更容易跑通;如果你用了ES Module,就必须开一个本地HTTP服务器,否则浏览器会因为CORS限制拒绝加载模块文件。后面我会在实操章节专门讲这个。除此之外,GLM5.3的碰撞检测逻辑是最严谨的——它甚至计算了玩家包围盒和墙体包围盒之间的最小穿透深度,然后按穿透方向把玩家推出去。这种精度在简单迷宫里显得冗余,但在复杂地形里会很稳定。
2.4 表格对比总览
我整理了一张表,方便你一览三个模型首轮跑完后的对比情况。打分基于我上面说的五档维度,满分5分:
| 评测项 | Step 5 Preview | DeepSeek V4 Pro | GLM5.3 |
|---|---|---|---|
| 首轮可运行率 | 5 | 4 | 2 |
| 渲染正确性 | 5 | 4 | 4 |
| 交互流畅度 | 4 | 3 | 5 |
| 代码可读性 | 5 | 3 | 3 |
| 二次修复效率 | 5 | 4 | 4 |
| 总分(满分25) | 24 | 18 | 18 |
| 首轮代码行数 | 约420行 | 约300行 | 约640行 |
| 主要阻塞问题 | 跳跃高度不合理 | 相机视角翻转、碰撞过冲 | 模块依赖导致白屏 |
这个表格只代表第一轮,不代表最终结果。实际上经过两轮对话后,三个模型都能修复到可玩状态,但修复的体验完全不同。GLM5.3修复后的代码甚至比Step 5 Preview首轮版还要稳定,这说明模型的逻辑底子是好的,问题出在它对"简单场景"的过度预估。顺带提一句,我还拿大家聊得很多的doubao-seed-2.0-code试了一下同一个题目,它的代码风格介于DeepSeek和GLM之间,既有模块化意识又不会太重,但首轮也有一个小的命名空间冲突问题。由于本文主角是前三者,这里就不多展开了。
3. 完整实操:从出题到可玩游戏的落地过程
3.1 先统一环境:一个HTTP服务器能省80%的麻烦
在进入实操记录前,必须先讲清楚环境。三个模型里有两个生成的代码用了ES Module或依赖跨域资源,直接在Chrome地址栏输入file:///Users/xxx/game.html大概率会报"CORS policy"或"Cross origin requests are only supported for protocol schemes"。所以我做的第一件事是在游戏目录下启动一个本地HTTP服务器。
最偷懒的办法是Python自带的SimpleHTTPServer。在游戏文件所在目录打开终端,执行:
python3 -m http.server 8000然后在浏览器访问http://localhost:8000/game.html即可。如果你不熟悉Python,也可以用VS Code的Live Server插件,右键HTML文件直接Open with Live Server。这里有个容易踩的坑:Windows上如果执行python找不到命令,要试py -m http.server 8000。服务器端口只要不是8000也没关系,但别用8080,常见软件占用的概率更大。
3.2 第一轮验收:三个文件在本地跑起来的亲测记录
我把三个模型生成的HTML分别保存为step5.html、deepseek.html、glm53.html,然后逐个访问。
Step 5 Preview的文件加载后,场景渲染快,画面里出现了迷宫、绿色立方体和黄色八面体。光源用的是HemisphereLight加DirectionalLight,颜色还原不错。我按W、A、S、D移动,手感正常,碰撞到墙体会明显停止,没有穿透。来回收了几次测试,唯一难受的是空格跳跃完全无意义——跳起来1.2单位高度,落回去,对于迷宫内的移动没有一点影响。这不算bug,但属于提示词里"空格跳跃"要求没有真正生效。
DeepSeek V4 Pro的文件加载后画面也正常,但相机朝向问题如前所述。我在迷宫里转了十几秒就有点晕。此外它墙壁生成用的是循环里写死的二维数组,数组里的0和1代表地面和墙体,这个思路是对的,但数组非常小,导致迷宫空旷,没有迷宫感。我数了一下一面大墙都没有,更像是几个独立的柱子。另外它的宝石刷新机制居然会在墙内刷出来,我第一次碰到宝石时,听到得分增加,但宝石本身陷入墙体一半,视觉上觉得钻石卡在了墙缝里。这个问题是我后续二次修复时重点反馈的。
GLM5.3的文件打开后一片灰色,控制台报错:Uncaught TypeError: Failed to resolve module specifier "three"。这是因为模块导入路径没有写完整,它用了import * as THREE from 'three',而浏览器需要的是完整URL。解决办法是在HTML里把import 'three'改成import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js',或者把所有import都改成直接引用CDN绝对地址。改完之后页面能渲染,逻辑运行正常。我在第二轮对话里让GLM5.3自己修复这个问题,它给出的建议确实是"请使用本地HTTP服务器并修改import路径为完整URL",此后再无白屏。
3.3 游戏增强:给Step 5 Preview版加上计分板、移动端触控和音效
评测完三个模型的初始能力后,我选了Step 5 Preview的代码作为基础,进行了两轮功能增强。第一轮要求它加一个计分板,显示当前帧率、耗时和宝石得分。它的实现方案是在页面右上角画了一个透明的<div>,然后用requestAnimationFrame里的回调更新内容。这个做法很轻,没有引入额外的开发库,值得学习。
第二轮我提了一个更有挑战性的需求:给游戏加上移动端触控支持,包括虚拟摇杆和触摸跳跃按钮,这样就能直接打包成安卓APK。这里涉及一个热词——开源安卓3d游戏。说实话,用Three.js写Web游戏再套WebView打包成APK,是成本最低的开源安卓3D游戏方案之一。具体流程是:先让Step 5 Preview加入触摸事件监听,分别处理摇杆区域的拖动和跳跃按钮的点击;封好后在安卓浏览器里测试触摸响应;最后用Capacitor或Cordova包装成Android工程。我实测用平板模式打开Step 5 Preview增强版,触控操作流畅度勉强能接受,摇杆反馈稍有点延迟,但主要原因是CDN版Three.js在移动端加载较慢。如果要发布,建议把Three.js替换成本地文件。
Step 5 Preview的移动端代码实现得不错。它用touchstart、touchmove、touchend记录起始坐标,计算位移向量映射到角色移动速度,而不是简单绑定按键。这个方案的好处是支持模拟摇杆的连续方向,比四方向按键体验好很多。它还自动检测了触摸屏,检测方式是('ontouchstart' in window),实测在安卓Chrome和微信内置浏览器里都生效。
3.4 性能分析:帧率、内存、代码体积真实数据
我用DevTools的性能面板分别测了三个模型最终可玩版本的帧率。测试环境是MacBook Pro,Chrome版本126,游戏运行1分钟记录平均帧率:
| 版本 | 平均FPS | 最低FPS | 页面内存占用量 | HTML文件大小 |
|---|---|---|---|---|
| Step 5 Preview增强版 | 60 | 52 | 约85MB | 28KB |
| DeepSeek V4 Pro修复版 | 60 | 44 | 约90MB | 19KB |
| GLM5.3修复版 | 60 | 35 | 约95MB | 41KB |
这个结果说明,对于这种规模的3D场景,三个模型的性能差距都不致命,真正的瓶颈不在代码效率,而在Three.js自身的渲染开销。最低帧率出现时基本都是玩家高速转向或宝石刷新瞬间,GLM5.3因为碰撞修正逻辑复杂了一点,在场景切换时会有几毫秒级的卡顿。但底盘都算稳。代码体积差距很有意思:Step 5 Preview虽然原始代码420行,但结构清晰;DeepSeek V4 Pro代码最短,可读性拖了后腿;GLM5.3则因为过度抽象膨胀到640行,即使修复后体积也没有降下来。
4. 常见问题与排查技巧实录
4.1 WebGL上下文丢失与纹理跨域
这三个模型生成的代码都是从CDN加载Three.js,如果你在本地网络不稳定,偶尔会碰到WebGL上下文丢失,表现为画面白屏且控制台打印Context Lost。这个问题绝大多数时候不是代码问题,而是浏览器为了释放GPU资源主动杀掉了上下文。我在测试GLM5.3修复版时遇到过一次,解决方式是换用本地Three.js文件,以及减少浏览器标签页数量。如果你在开发机上也遇到,可以试试在页面加载时添加一行THREE.ColorManagement.enabled = false,少数情况下能规避渲染器初始化异常。纹理跨域则常见于你后续给迷宫墙面贴图的时候,如果直接引用file协议或CDN地址,Chrome会拦截,正确做法是把图片放到和HTML同目录下,再用相对路径引用,并确保从HTTP服务器访问。
4.2 碰撞检测的经典BUG:穿模和卡墙角
模型生成的碰撞代码里,最经典的问题是穿模,尤其是高速移动时,单帧位移大于墙厚的一半,就可能导致角色直接瞬移到墙另一侧。我测试时把速度从5调到20,三个版本都会出现不同程度的穿模。根本原因在于碰撞检测是一次性的,没有做连续碰撞检测(CCD)。对于2单位高度的墙和0.8单位的角色,5单位/秒的速度在60帧下每帧位移约0.08单位,小于0.5的安全阈值,所以表现稳定。一旦帧率波动,位移就会超过阈值,进而穿模。
我的建议是:如果你要做高速动作游戏,不要依赖模型首轮生成的碰撞代码,必须要加一步"对上一帧位置与当前帧位置做线段扫描"。最简单的实现是判断起点和终点是否被墙隔开,如果隔开,就回退到上一帧位置。这个补丁很小,但能解决90%的穿模问题。至于卡墙角,常见是因为碰撞处理后玩家被推进墙角,而代码没有提供"滑墙"机制。Step 5 Preview的轴分离碰撞天然解决了卡墙角问题,另外两个版本在高速度下会在墙角抖动,修复方法是把玩家位置修正为沿X轴和沿Z轴分别计算,而不是一次性将两个方向合并处理。
4.3 移动端安卓实测:触控与性能兼容那些坑
如果你打算把这类游戏放到安卓端,我踩过的坑可以列一个速查表:
| 现象 | 原因 | 解决 |
|---|---|---|
| 页面白屏但桌面正常 | 安卓WebView版本过低,不支持WebGL2 | 在webglcontextcreationerror事件里检测失败后降级到WebGL1,或者升级系统WebView |
| 声音无法自动播放 | 移动浏览器自动播放策略 | 在用户第一次触摸屏幕后再调用audio.play() |
| 虚拟摇杆漂移 | touchmove事件没做preventDefault | 在touchmove中调用event.preventDefault(),并给canvas设置touch-action: none |
| 加载缓慢 | CDN资源在弱网下不稳定 | 把Three.js和贴图全部打包到本地assets目录 |
我在平板上实测Step 5 Preview增强版,用touch-action: none修复了画面拖拽的问题。如果你用的是Capacitor打包,需要在capacitor.config.ts里把server.cleartext设为true,否则无法在安卓真机上访问HTTP资源,默认只能访问HTTPS。
4.4 部署GLM5.3自建推理时,vLLM镜像版本怎么选
讲一个偏离游戏但很多人问到的延伸问题。前面提到我用的是GLM5.3的网页版/API,但如果你打算本地部署GLM5.3然后让游戏生成服务也走自己的推理接口,就会遇到"glm5.3使用vllm哪个版本的镜像"这个问题。我的经验是:不要用老版本vLLM。GLM5.3的模型结构和训练方式决定了它依赖较新的算子,比如MLA和GQA的优化,旧版vLLM兼容性差,会报Unsupported attention backend或Cuda error: no kernel image is available。建议直接使用vLLM官方最新stable版本,最好选对应commit构建的镜像,而不是最新的dev版,因为dev版容易有接口变化。我自己的部署习惯是固定使用vllm/vllm-openai:v0.6.3.post1镜像,在对GLM5.3实测时能正常加载。如果你想要更稳定的效果,可以去Hugging Face上搜GLM5.3官方推荐镜像名,官方一般会在模型卡里备注兼容版本,那个信息比任何人给你的都靠谱。
还有一个小坑:如果你用Docker部署vLLM,注意显存不够时优先调低--max-model-len而不是调低--gpu-memory-utilization,因为GLM5.3的长上下文能力依赖KVCache预先分配,后者调太低可能导致推理速度断崖式下跌。这个我在调优时印象很深刻。
5. 最终结论和一点个人体会
三轮玩下来,我对这三个模型的定位有了比较明确的判断。Step 5 Preview给我的感觉是"懂前端开发的产品经理"——它生成的代码不仅正确,而且非常照顾使用者体验,比如首次就规避了宝石刷新进墙体的问题,碰撞分离轴处理,这些点很多有经验的开发者第一次都想不到。DeepSeek V4 Pro优势在于生成速度快,输出文本口语化,对于不需要精准架构的小工具很顺手,但复杂场景下代码组织和Bug修复效率一般。GLM5.3像是一个"后端架构师"——默认给你搭好整栋楼,但你把楼放到浏览器里时才发现它默认用的是ES Module,需要你多花一部开服务器的功夫。
如果你非要在三个里选一个做一个3D游戏,我的建议是:快速原型阶段用Step 5 Preview,它的首轮完成度最高;如果你倾向于在Agent流程里多次迭代,DeepSeek V4 Pro的修复响应速度会让你更省心;如果你需要最后交付的代码有清晰的架构,愿意花成本做首轮调试,GLM5.3出来的成品扩展性最好。
最后分享一个我使用AI做3D游戏时悟到的小技巧:不要只给模型一个需求清单,可以在提示词的最后加一句"请在生成代码前先用三句话说明你的设计思路,包括如何组织代码结构和如何处理碰撞检测"。就这么一句话,能让三个模型的代码质量都提升一截。因为模型在生成前会先形成设计计划,而不是急着喷代码,出来的结果更有条理。Step 5 Preview默认就带了这个特性,DeepSeek V4 Pro会在你要求后模仿,GLM5.3则会真的写出方案文档再开写——但它的方案文档甚至比代码还有用。
老实说,3D游戏对AI来说已经不是新鲜挑战,真正拉开差距的是在"不完美的首轮输出"之上的迭代能力。Step 5 Preview这次让我爽到的主要不是它首轮跑通了,而是它在后续两轮里几乎不需要我反复解释问题就能准确修改。这一点,是判断模型是否能做"AI驱动原型开发"的关键分水岭。以后我再有类似的小项目,应该会优先拿它起步了。