前阵子圈子里流传一个说法:顶级模型能做到“一句话生成一个能玩的 QQ 飞车”。我一开始当标题党看,直到自己动手试了一次。这里说的 QQ 飞车,不是指腾讯那个端游,而是模型根据一句需求描述,直接在浏览器里生成的一个类 QQ 飞车竞速小游戏。整个流程从输入提示词到页面弹出、摁下方向键跑起来,我这边花了不到十分钟。而且不只是“能打开”,漂移、撞击减速、AI 对手、圈数计时这些核心玩法全都有。今天把这件事拆开讲清楚,包括模型是怎么理解这句话的、初始代码长什么样、我踩了哪些坑,以及如果你也想复现,应该怎么一步步操作。
1. 项目拆解:AI 写“QQ 飞车”到底在写什么
1.1 一句话需求背后隐藏的技术点
很多人以为“写个 QQ 飞车”是一句简单的自然语言,实际上这句话落到代码层面,至少包含七八个独立的技术模块。我们可以把一段合格的提示词拆开看,它其实是在描述一个完整的 2D 赛车游戏闭环:
- 游戏渲染:用 Canvas 绘制赛道、草地、车辆、AI 车、HUD 信息。
- 玩家控制:键盘方向键控制车辆加减速和转向,需要处理按键按下与弹起的持久状态。
- 物理运动:车辆有速度、加速度、摩擦系数、转向半径,漂移需要额外的侧滑与恢复逻辑。
- 碰撞检测:车辆不能开出赛道边界,车与 AI 车相撞要减速,车与场景元素(比如路肩)要有反馈。
- AI 车逻辑:AI 车需要沿赛道自动行驶,躲避障碍,并且不能完全瞬移或穿模。
- 游戏状态管理:开始界面、倒计时、进行中、完成圈数、结束结算。
- 视觉与音效:赛道颜色、车灯、简单音效(虽然模型有时会忽略,但你可以让它补)。
换句话说,一句话的背后是一整套“最小可玩竞速游戏”的模块列表。顶级模型的价值在于,它能把这句话自动映射成代码结构,而不是像早期 AI 那样只生成一个“方块在画布上乱跑”的样板。
1.2 为什么拿竞速游戏当 AI 编程能力的试金石
竞速类游戏非常适合用来测试大模型的代码生成能力,原因有三个。
第一,状态反馈极快。玩家按下方向键,车辆立刻在屏幕上移动,任何一个物理系数不对,肉眼都能马上发现。相比生成一个管理系统或者算法题,游戏是“体验型”产物,好不好玩、顺不顺手一眼就知道。
第二,核心逻辑相对收敛。赛车游戏不需要复杂的剧情分支、数据库、网络同步,核心逻辑集中在“车辆状态更新 + 画布重绘”这一个循环里。模型只要把主循环写对,整个游戏就转得起来。
第三,可玩性门槛低但上限高。一辆车能跑、赛道能转圈,就已经算“能玩”;再加上漂移、道具、AI 对手,就从 demo 变成了“有点意思”。这种渐进式需求非常适合跟 AI 迭代对话:第一版不行,就让 AI 改参数,改一版试一次。
这也是为什么最近很多人拿“AI 生成赛车游戏”当大模型能力基准测试。它不像数学题有标准答案,也不像文章写作那么主观,它是一个“感觉对不对”就能判断的领域,天然适合非程序员去体验 AI 编程的能力边界。
2. 模型选型与提示词设计
2.1 我自己用的模型选择思路
标题里说“顶级模型”,这个描述其实有点模糊。我实际测试下来,只要是目前公开可用、支持长上下文、能直接生成完整 HTML 文档的旗舰级对话模型,都能做到类似效果。我用过 Claude 的 Artifacts 模式生成单个 index.html,也用过 GPT-4o 做二次修补,还试过国产的 DeepSeek 用纯文本输出再手动复制成文件,结果都跑通了。
区别在于体验:
- Artifacts 模式最省事,生成之后直接预览,无需本地建文件。
- 普通对话模型输出的代码可能被截断,需要分几次补全,或者用“继续输出”让它把剩余代码写完。
- 模型版本敏感:同一个模型,老版本可能只给你画一个静态赛车图片,新版本才会一次性生成完整游戏。
所以如果你想复现,别纠结“哪个模型最强”,选一个你手上能稳定访问的旗舰模型就行。关键是提示词怎么写,以及后续怎么调教。
2.2 一句话提示词模板,以及为什么有效
所谓“一句话”,并不是真的只输入“帮我写个 QQ 飞车”六个字。标题是为了传播,实操里最合理的“一句话”是一段密集的、包含所有关键约束的需求描述。我的模板大致是这样:
“用 HTML + CSS + Canvas 写一个类似 QQ 飞车的 2D 俯视角赛车游戏。要求:有环形赛道、草地背景、3 辆 AI 对手车;玩家用方向键控制,空格键氮气加速;实现漂移(按 Shift 漂移),撞击 AI 车会减速;有圈数计时和排名显示;有开始界面和重新开始按钮;所有代码放在一个 index.html 文件里,可以直接在浏览器打开运行。”
这段提示词看似很长,但从模型角度看仍然属于“一句话”的范畴,因为它没有分点展开,就是一个自然段。但它为什么能生效?关键在于它给出了完整的信息边界:
- 技术栈:HTML + CSS + Canvas,模型就不会去生成一个 React 项目或 Python 程序。
- 玩法清单:环形赛道、AI 对手、漂移、氮气、圈数计时,模型会把这些都作为功能需求对待,而不是自由发挥。
- 交付物形态:一个 index.html 文件,方便我直接打开验证。
如果只说“写个赛车游戏”,模型大概率会给你一个非常简陋的、只有一辆车在直线上跑的页面。因为信息越少,模型越倾向于用最省事的实现方式来满足模糊指令。大模型天然是“按需交付”的,你要把隐性需求变成显性需求。
2.3 模型如何把自然语言变成可运行代码
理解模型的工作方式,能帮你更好地调试结果。顶级模型接收这段文字后,并不是直接逐字翻译,而是先在内部建立一个“代码蓝图”:
- 识别到“ Canvas”,知道要用 2D 上下文。
- 识别到“赛车游戏”,自动关联到经典的车辆运动模型:位置、速度、朝向角、角速度。
- 识别到“ AI 对手”,会去寻找一种简单的自动寻路方案,比如“轨道点跟随”或“边界约束随机驾驶”。
- 识别到“漂移”,会尝试在转向时增加一个横向滑动速度,并在松开方向键后逐渐恢复。
然后模型会把它学过的无数赛车游戏代码片段重组起来,生成一套“看起来很像样”的项目。这个过程中会有两个问题:一是它可能高估自己的能力写出理想化代码,二是它可能对某些细节偷懒。之后你实际运行时就会发现,光影效果齐全,但车轮胎居然不会动。这些都需要进入下一节说的“实操调优”。
3. 实操实录:从生成到能玩
3.1 模型初版代码的核心结构
我用上面的提示词跑出来的初版,是一个一千多行的 index.html,结构大致如下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>极速飞车</title> <style>... 页面布局与画布样式 ...</style> </head> <body> <canvas id="gameCanvas" width="900" height="600"></canvas> <script> // 1. 全局变量:车辆数组、键盘状态、圈数、计时 // 2. Car 类:位置(x,y), 角度(angle), 速度(speed), 转向角 // 3. Track 类:预生成赛道轮廓点,draw 方法画路肩和草地 // 4. 主循环 gameLoop:update() 更新物理,draw() 绘制画面 // 5. 键盘事件监听:keydown/keyup 修改键盘状态对象 // 6. AI 车逻辑:沿预设路径点移动,带一点随机偏移 // 7. 碰撞检测:玩家车 vs 边界、玩家车 vs AI 车 </script> </body> </html>这个架构是合理的,说明模型知道游戏开发的基本套路。关键是在update()函数里,它用了 delta 时间(毫秒)来计算位移,而不是固定每帧移动多少像素。这一点很关键,因为不同电脑刷新率不一样,如果写死每帧像素,60Hz 和 144Hz 屏幕上的速度会差一倍。
初版能跑起来,但手感很“飘”:转向灵敏度太低,速度起来了车子几乎不转弯;AI 车会连续撞墙,然后卡在赛道边缘抖来抖去。我当时的判断是:核心框架没问题,但物理参数和碰撞边界需要人手动调。
3.2 让“能玩”成立的三个关键点
第一版能跑不代表能玩,真正让它“玩起来”要解决三个问题。
关键点一:键盘控制要稳定。模型生成的代码里,键盘监听用的是event.keyCode,这没问题,但要注意它是否加了event.preventDefault()。如果不加,按空格键会滚动页面,按方向键也会导致页面滚动,游戏画布虽然接收了按键,但页面跳动很影响体验。我第一版就遇到了空格键让页面反复刷新上下的问题。解决办法是在keydown和keyup里加上e.preventDefault()。
关键点二:碰撞检测要宽容。模型生成的边界碰撞逻辑通常是检查车辆四个角是否超出赛道多边形。但车是有宽度的,如果检查点设得过紧,车辆会经常在赛道边缘“卡死”。我的做法是给赛道边界生成一个“内缩多边形”,即边距向内偏移 15 像素,车辆碰撞检测用内缩后的多边形判断。这样既不会明显穿帮,车又能顺畅压路肩。这个思路模型不会主动给你,需要你从游戏开发的经验里反推。如果你不懂碰撞检测原理,最简单的替代方案是:当车辆坐标超出画布边界时,从上一帧位置拉回来,并把速度乘以 -0.5 模拟反弹。虽然不够精确,但效果立竿见影。
关键点三:车辆物理参数要合理。模型生成的车辆初始加速度可能设定为 0.1(每帧速度增量),转向角速度可能是 0.03,这会导致车像溜冰。我调参的基准策略是:先保证直线加速感,再调转向,最后调摩擦。建议把速度上限设为 8~10 像素/帧(在 60fps 下),加速度 0.15~0.25,摩擦系数 0.98(每帧速度乘 0.98 模拟阻力),转向角速度 0.05~0.07。这组参数在 Canvas 坐标下通常能有比较“街机感”的手感。注意不是所有模型生成的车都用这套参数,但你可以拿它作为起点。
3.3 实测调优记录:漂移、AI 与视角
调好基础手感后,我开始体验“漂移”和“AI 对手”,这俩才决定它像不像 QQ 飞车。
漂移这个功能,模型第一版实现得很简单:按住 Shift 时,车的横向摩擦系数降低,并额外增加一个侧滑速度。实际效果是快速过弯时车子会往外甩,松开 Shift 后立刻恢复抓地力。问题在于:漂移时转向会变得不灵敏,经常一甩就直接撞外墙。我把漂移期间的转向角速度从 0.05 提高到 0.09,相当于漂移时方向盘更“重”但有效转幅更大。实测下来,90° 弯道可以漂过去,手感有点 QQ 飞车里“点满漂移”的味道了。
AI 对手是另一个大坑。模型生成的 AI 车能用预设路径点移动,但路径点是直线连接,导致 AI 车碰到弯道时出现“折线走位”,看起来很生硬。我把路径点细分成曲线点,每两个原始路径点之间用二次贝塞尔插值生成三个中间点,AI 车顺着这些点走,过弯圆润很多。同时给每辆 AI 车一个随机的速度波动(比如 ±15%),避免三辆车永远排成一条直线,跑起来更像真人对抗。
最后是视角问题。QQ 飞车其实是半追踪视角,俯视角但如果车辆贴到屏幕边缘,镜头会滑动。模型生成的代码默认是固定画布,车跑到上边就看不见。我让draw()函数里的translate和scale跟随玩家车的位置做了“追拍”,也就是把整个赛道画到以玩家车为中心的偏移坐标系上。这样开车时视野会跟着走,沉浸感强很多。追拍的实现也不复杂,就是在每次绘制前:
ctx.save(); ctx.translate(width / 2 - player.x, height / 2 - player.y); // 然后绘制所有场景物体 ctx.restore();这个操作让整个游戏从“看一个固定菜园子里的玩具车”变成了“坐在车里冲刺”。我觉得这一步提升值 50% 的体验。
4. 常见问题与排查技巧
实际调试过程中,我遇到了一堆问题,有些是模型代码本身的 bug,有些是我自己电脑环境的问题。整理成速查表,能帮你省时间。
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 页面能打开但车辆不动 | 键盘监听事件没绑定到 window,或者焦点在 iframe/按钮上 | 在window上绑定keydown/keyup,并在keydown里preventDefault() |
| 画面很模糊 | Canvas 尺寸用了 CSS 缩放,但实际像素分辨率低 | 根据devicePixelRatio调整 Canvas 宽高,或者干脆固定 900x600 并禁止缩放 |
| 车开出去就回不来 | 缺少边界碰撞,或者碰撞检测过于宽松 | 生成内缩多边形做碰撞,或强制钳制坐标在赛道范围 |
| AI 车互相重叠 | AI 车之间没有碰撞检测 | 在 AI 车更新后,遍历所有车对做矩形相交检测,重叠时把后车沿连线方向推出去 |
| 按空格导致页面滚动 | 未阻止默认行为 | 键盘事件里e.preventDefault(),同时确保事件绑定在window上 |
| 游戏运行一段时间变卡 | 内存泄漏,通常是每次绘制都创建对象 | 把绘制中的临时对象抽成全局或复用数组,避免每帧 new |
| 模型生成的是 Python/pygame 代码 | 提示词没说清楚技术栈 | 提示词里明确“所有代码放在一个 index.html” |
4.1 第一版代码“跑不起来”的排查思路
我遇到的第一个问题是:模型生成后我直接把 HTML 拖进浏览器,结果白屏。打开控制台,报错是Uncaught SyntaxError: Unexpected token '<'。原因是模型用 Markdown 代码块把 HTML 包起来了,我手动复制时把html标签前后的也复制进去。这种问题很低级,但新手极易踩。解决办法:复制代码时要注意只复制代码块内部的内容,别把语言标记和结尾的带进去。
还有一种“跑不起来”是黑屏但没报错,这是因为 Canvas 的宽高被 CSS 设置成了 100%,但 JS 里canvas.width和canvas.height用的是默认 300x150。检查一下 JS 里是否在init函数中设置了宽高,如果没有,手动加上:
canvas.width = 900; canvas.height = 600;4.2 体验类问题的调参心得
能跑起来之后,主要问题集中在“手感”。我自己调参的时候总结了一套口诀:加速小了肉,转向小了滑,摩擦大了硬,摩擦小了飘。拿不准的时候,就用前面提到的基准参考值去微调。速度上限 8、加速度 0.2、转向 0.06、摩擦 0.98,这四个数组合起来大多数情况下至少是“能玩”的。
另一个容易忽略的是驾驶辅助。很多时候玩家不是嫌车太慢,而是嫌转向太难。你可以加一个简单的“转向辅助”:当玩家按住方向键时,如果车头和赛道中心线的夹角过大,自动增加转向角速度。我后来在后处理阶段给 AI 车也加了同样的辅助,AI 就不会频繁撞墙了。
4.3 关于“让 AI 自己修 bug”的小技巧
遇到单个 bug 时,我不建议直接改代码,而是把报错信息和问题描述原封不动丢回给模型,让它自己提修复方案。例如:
“我的赛车游戏运行时报错:cannot read property 'x' of undefined,位置在 update 函数 AI 车数组那里,可能是什么原因?请给出修复后的完整 update 函数。”
模型通常会马上定位到“数组越界”或“对象没初始化”这类问题。这个方法比自己在几百行代码里找快得多。但要注意:模型给出的修复代码有时会破坏其他功能,所以每次让 AI 修完,都要把整段代码重新过一遍,确认没有引入新的 bug。我用这个迭代方式,半小时内就把一个小 bug 修复了。
5. 从“能玩”到“好玩”的扩展建议
5.1 让 AI 自己 Review 自己的代码
大部分顶级模型已经具备代码审查能力。我在手感调到基本满意后,会把完整代码复制一份,发给同一个模型,让它“以资深游戏开发者的身份,找出这段代码里潜在的性能问题和体验问题,并给出优化建议”。这一步能发现很多初版的问题,例如:
- 大量
setInterval导致定时器叠加 - 没有做
requestAnimationFrame的兼容降级 - 绘制赛道时每帧重新计算贝塞尔点,性能浪费严重
模型的 Review 建议不一定全对,但它能帮你快速建立“找问题”的思路。对我最有价值的一条是建议把赛道预计算成像素级离屏 Canvas,绘制时直接drawImage贴图,帧率从 40fps 上升到稳定 60fps。不用懂后端,也不用懂编译原理,就能感觉 AI 辅助开发带来的效率提升。
5.2 玩法扩展路线
基础版能做出来之后,后面加内容会越来越顺。按优先级排列,可以这样扩展:
- 道具系统:在赛道随机位置生成加速带、飞碟减速道具、导弹攻击道具,模型写一个简单的
道具类加碰撞触发逻辑即可。 - 排行榜与重播:保存最佳圈速到
localStorage,下一次打开还能看到历史记录。 - 多赛道:用数组存多条赛道的路径点,切换赛道时重新生成。
- 音效:用 Web Audio API 生成简单的引擎轰鸣音,不需要外部音频文件。
- 触屏支持:监听
touchstart/touchend,把触摸方向映射成左/右/加速,手机也能玩。
每一步都可以用“向模型提需求”来完成。我个人试过给模型说:“加一个香蕉道具,吃到后玩家车原地打滑 1 秒”,它真的实现了,虽然打滑动画比较简陋,但机制是完整的。这就是模型辅助游戏开发的实用价值:你不用等自己掌握全部 Canvas 绘图 API,就能快速验证玩法想法。
5.3 适合哪些人复现,以及我的最终体会
如果你想复现这个项目,我建议你至少懂一点 HTML 和 JavaScript 基础,哪怕只是能看懂变量和函数。如果你完全零基础,也不是不能玩,但碰到小问题自己排查会比较痛苦。复现的路径很简单:选一个你用得顺手的顶级模型,把 2.2 节的那段提示词复制进去,拿到生成的 HTML 文件在浏览器打开。先别急着改,把基础手感跑顺,再一步一步加需求。
最后说点个人体会。AI 写的游戏,本质上是一个“极速原型”,它把从零到可玩的时间压缩到了几分钟,但“好玩”这部分,仍然需要人投入判断。漂移手感、AI 走线、镜头追踪,这些都需要实际开几圈才能确定好不好。模型可以生成一个骨架完整、逻辑没毛病的 demo,而真正的灵魂,是在一次次试驾和调参里注入的。这也是为什么我觉得这个方向特别有意思:AI 主要负责“写代码”,人主要负责“玩出来”。按这个思路,AI 游戏开发的大门,对所有人都开了一条缝。