把一句“帮我写一个能玩的赛车小游戏,手感接近 QQ 飞车那些老牌竞速游戏”直接丢给当前最强的 AI 模型,等不到三分钟,浏览器里真就弹出一个能加速、能漂移、带计时和圈数的横版赛车。这不是发布会中场放的演示片段,是我上周连着测了十几轮之后确定下来的稳定玩法。整个过程不需要装编辑器、不需要拉工程模板、不需要人工补代码,一句提示词就是全部需求文档。
这篇文章我打算把整个实验完整拆开:提示词到底怎么写、模型生成的核心代码该怎么理解、游戏跑不起来怎么让模型自己修、参数怎么调才像“正经赛车游戏”。我会把实操过程中踩过的坑和试出来的技巧一起放进去,不管是游戏开发者想做原型验证,还是想用 AI 做小游戏玩玩的爱好者,都能照着这条路走一遍。
1. 项目整体设计与思路拆解
1.1 为什么一句提示词能生成可玩的赛车游戏
先说结论:这不是模型“凭空创作”了一个游戏,而是它从海量训练语料里准确回忆并组合出了一个成熟模式。HTML5 小游戏是开源社区里数量极多的代码类型,顶级模型在预训练阶段见过大量“单文件 HTML + Canvas + 原生 JavaScript”实现的赛车、贪吃蛇、俄罗斯方块代码。当你用一句描述触发它时,模型做的不是编程,而是以极高的概率重组出这类代码的典型结构。
理解这层原理特别重要。它决定了我的策略:不追求让模型“发明”新玩法,而是让它稳定复现一个成熟的游戏骨架,然后我再通过追加指令不断修细节。这样做的好处是成功率极高,因为模型对“赛车游戏 + 画布 + 主循环 + 键盘监听”这类组合太熟悉了,几乎不会出现思路上的偏离。
这也解释了为什么我推荐用原生 Canvas 而不是某个重型框架。框架版本迭代快、API 变化大,模型可能混用不同版本的语法,反而容易出错。原生 JavaScript 是训练数据里最稳定的部分,模型输出时踩雷概率最低。
1.2 技术选型:单文件比多文件靠谱得多
刚开始测试时,我试过让模型生成“一个 index.html + 一个 game.js + 一个 style.css 的完整项目”。结果很不理想:模型经常在 JavaScript 文件里使用未定义的函数,或者 HTML 里忘记引对路径,生成的代码零零散散。后来我把目标统一改成“单个 HTML 文件,CSS 和 JavaScript 全部内嵌”,问题一下消失了。
原因不难猜。模型在单文件输出时能看到完整上下文,它知道某个函数在哪个位置定义,也就不会出现在多文件场景下“跨文件”引用出错的尴尬。对 AI 编程来说,限制输出范围反而能提升正确率。单文件还有额外好处:保存成.html后双击浏览器直接运行,不需要启动本地服务器、不需要装 npm 包,真·零环境依赖。
如果你想让游戏在手机上也能玩,提示词里最好写明“适配手机和电脑双端操作”,模型会用键盘事件和触摸事件各写一套逻辑,这点我后面会展开。
1.3 提示词不是玄学,是压缩版的需求文档
很多人以为“一句提示词”就是随便说句话,比如“做个赛车游戏”。我试过这种极简输入,模型确实能输出代码,但生成结果考察下来要么没有计时、要么没有碰撞检测、要么画面拉伸变形。后来我把一句提示词改造成“结构化的压缩需求文档”,生成成功率几乎翻倍。
我的提示词固定包含六层信息:角色定义、游戏目标、操作方式、视觉风格、功能清单、验收标准。把这些信息压缩在两百字以内,模型就能得到足够明确的输出指引。这不是什么神秘技术,本质上就是让模型少猜一步,把所有模棱两可的空间都堵死。
下面这条是我测试下来最稳定的一版提示词,后面所有实操都围绕它展开:
你是一名资深游戏开发工程师。请用单个 HTML 文件实现一个类 QQ 飞车风格的横版赛车小游戏:支持上下左右方向键控制车辆,右下角实时显示速度和计时,按 Shift 键触发氮气加速并显示尾焰特效,道路使用纵向滚动的虚线表现前进感,路旁有红白相间的赛道边界和绿色草地背景,障碍物为红色锥桶,碰撞后车辆明显减速;左上角显示当前圈数和总圈数,完成 3 圈后显示排名并重新开始;使用 Canvas 绘制,代码放在一个 HTML 里,同时适配键盘和手机触摸操作。最后在文件末尾用注释列出所有可以调整的参数。
请特别注意“最后在文件末尾用注释列出所有可以调整的参数”这句话。它看起来不起眼,却是我后面实现“控制台调参”的关键伏笔,后面章节我会讲这个设计带来的好处。
2. 核心细节解析与实操要点
2.1 提示词模板拆解:每一句话都对应一段代码
我们还是把上面那条提示词逐句拆开,理解每个短语最终变成了代码里的什么部分。
- “角色定义”对应模型输出的整体代码风格。它会用面向过程的写法还是面向对象写法,开局就定了。实测用“资深游戏开发工程师”这个角色,模型更倾向写出结构清晰、注释完整的代码。
- “横版赛车小游戏”限定了视⻆。模型不会给你写成俯视 45 度或第一人称 3D,它会在画布上直接绘制一个自上而下可见的竖屏赛道,车辆纵向移动,背景元素向下滚动模拟前进。
- “右下角显示速度”让模型创建了一个计速变量,然后通过
ctx.fillText实时绘制到 Canvas 上。这块逻辑不复杂,但没有明确要求时模型经常省略。 - “按 Shift 键触发氮气加速并显示尾焰特效”是对交互和视觉的强约束。模型需要同时实现按键检测、速度倍率切换、粒子或颜色渐变效果。
- “纵向滚动的虚线表现前进感”是决定游戏手感的核心。横版赛车游戏里车辆本身是不动的,动的只是背景线条和路边装饰,搞懂这个就能理解整个游戏循环。
- “用注释列出所有可以调整的参数”则是给后续调参留的后门。模型会把速度上限、摩擦力、加速系数这些常量的定义集中到文件顶部或底部的一个配置对象里。
我自己写提示词时还有一个习惯:把“适配手机触摸操作”放在最后一句。因为这时候模型已经写完了键盘逻辑,再看到触摸要求,通常会在已有代码上追加 touch 事件处理,而不是从头重写。
2.2 核心代码块解析:看懂这几段你就看懂了整个游戏
模型生成的代码通常有几百行,新手拿到手可能直接懵。其实核心就四个模块,我把它们分别解释清楚。
第一块是游戏主循环,通常用requestAnimationFrame实现。每一帧依次执行“清空画布 -> 更新车辆状态 -> 更新背景滚动 -> 检测碰撞 -> 绘制全部元素”。这是所有 Canvas 游戏的地基。模型生成的主循环大同小异,区别只是更新和绘制的顺序。
第二块是车辆物理模型。这里有个约定俗成的简化方案:车辆有一个速度变量,按下加速键时速度增加,松开时受摩擦力衰减,转向时车辆在 x 轴方向偏移。顶级模型写出来的代码你去看,大概率是speed += accel * dt这样的模式,配合最大速度上限和横向边界钳制。
第三块是滚动背景。赛车游戏要表现“前进感”并不需要真的移动车辆,而是让地面虚线、路肩、草地背景以固定速度向下移动,循环回到顶部。模型一般维护一个offsetY变量,每帧增加speed * timeScale,超过画布高度后取模归零。
第四块是碰撞检测。简单实现多用“距离判断”或“包围盒判断”,比较车辆与锥桶的坐标距离,如果小于阈值就触发减速效果。理解了四个模块,后面做任何玩法扩展都清楚该在哪个模块追加代码。
2.3 修 bug 的正确姿势:把控制台报错直接喂回给模型
程序员的直觉是拿到代码自己动手改,但 AI 生成游戏这条链路里最高效的修 bug 方式是“把问题原样描述给模型”。我总结了一套标准流程:先在浏览器里运行,打开开发者工具的控制台,把红色报错信息复制下来,连同“我按了什么键、画面变成什么样、我希望看到什么”一起发给模型。
这里有一个关键细节:要告诉模型“只给出修改建议或补丁,不要重写全部代码”。如果不加这句,模型很可能输出一大段完整代码,让你从头替换,反而破坏之前已经调好的部分。实测加上这个约束后,模型会精准定位到某个函数,给出一段十行以内的修复代码,粘贴替换就完事。
还有一个常用技巧:当模型修复一个 bug 时,把它输出的新代码片段和原有代码段一起放进对话上下文,要求它“基于当前版本的完整代码来修改,不要遗漏之前的改动”。这样可以避免模型“失忆”,防止它改好一个问题却把之前的功能弄丢了。
3. 实操过程与核心环节实现
3.1 完整提示词与生成结果实录
我按 2.1 节的提示词模板,在某款主流大模型对话框中实际跑了一次。等待约 20 秒后,模型返回了一个完整的 HTML 文件,总行数约 450 行。我把代码保存为racing.html,双击打开,游戏直接运行。
初次生成的效果可以用“能跑但不好玩”来形容。车辆能加速、能转向、背景在滚动、计时器在工作,但存在的问题也很明显:路肩和草地纹理宽度不对导致画面左边有一条黑边;氮气加速时尾焰效果是用黄色圆圈的反复绘制实现的,视觉上偏廉价;碰撞锥桶后速度减得太猛,几乎瞬间停车,完全没有缓冲手感。
我把这三条问题打包发回给模型,并要求“逐条给出修复建议,不要重写全部代码”。模型分别给出了三处 patch:第一处把背景画布宽度与游戏画布宽度统一并在两侧补齐草地;第二处改用渐变和粒子数组优化尾焰;第三处把碰撞后速度乘以 0.7 改为乘以 0.92,并新增一段减速缓冲逻辑。我依次应用后,画面观感和手感都明显上了一个台阶。
整个过程耗时约二十分钟,其中真正手动操作的只有复制粘贴和保存文件。这个流程极其适合快速验证一个玩法创意:你想知道某个赛车机制好不好玩,不用写代码,直接把需求丢给 AI,几分钟后就能上手试玩。
3.2 数值参数调整与手感调校
模型生成完成后,文件末尾通常有一块参数配置区,看起来像这样:
const gameConfig = { maxSpeed: 12, // 最大速度 accel: 0.08, // 加速度 friction: 0.86, // 摩擦力系数,每帧乘一次 turnSpeed: 3.2, // 转向速度 coneDamping: 0.92, // 碰撞锥桶后的速度保留系数 boostFactor: 1.8, // 氮气加速倍率 bgScrollRate: 0.5, // 背景滚动速度比例 totalLaps: 3 // 总圈数 };调参的时候我遵循一个原则:每次只改一个变量,改完立刻跑一局感受手感,而不是一次改好几个参数导致不知道是谁影响了手感。下面是我的调参记录,提供给你参考:
| 参数 | 初始值 | 调整后 | 手感影响说明 |
|---|---|---|---|
| accel | 0.08 | 0.12 | 起步更灵敏,但提速过猛会让转向变飘 |
| friction | 0.86 | 0.9 | 松开按键后滑行距离变长,更接近赛车惯性 |
| maxSpeed | 12 | 14 | 极速更高,画面上背景滚动更快,刺激感上升 |
| turnSpeed | 3.2 | 2.8 | 转向稍微迟钝,配合惯性滑行反而更容易控制 |
| coneDamping | 0.92 | 0.95 | 碰撞锥桶后的减速更温和,不会瞬间停车 |
我个人最喜欢的组合是:较慢的转向速度配合较大的摩擦系数(即滑行更远)。这种搭配让车辆在过弯时有一种“滑着过弯再拉回来”的质感,几圈跑下来能感受到明显的操作层次感。反过来,如果转向速度太快、摩擦系数又太小,就会变成每次按方向键都猛摆头,手感非常生硬。
3.3 从“能跑”到“能玩”的增量优化
首版能跑之后,我尝试通过追加指令继续加新功能,验证模型的增量修改能力。我给模型的追加提示是“在当前代码基础上新增一个金币收集系统,金币随机出现在赛道中间,车辆碰到金币后播放音效并用声光反馈”。由于我在对话中包含完整代码和明确的追加位置,模型准确地在碰撞检测区块新增了一个金币数组和相关逻辑。
这个增量优化阶段最有意思的发现是:现代顶级模型已经具备很强的代码上下文保持能力,它不会要求你“把完整代码再发一次”,而是能主动定位到上一个版本的关键代码区块。只需要在追加指令里写明“基于当前代码版本”,模型就能输出精确的函数级修改建议。
我后续又追加了“添加一个简单的高分记录 localStorage 存储”和“增加一辆 AI 对手车自动行驶”。两个功能各花费约三分钟,且都能在原有代码上平滑集成。这说明 AI 生成游戏的能力不局限在一锤子买卖,而已经形成“生成 - 试玩 - 追加 - 再试玩”的闭环工作流。
4. 常见问题与排查技巧实录
4.1 典型问题速查表
我连续测试十几次,把遇到的高频问题整理成下表,每一条都附上对应的提示词修复方案:
| 现象 | 常见原因 | 有效的修复指令 |
|---|---|---|
| 游戏一打开就是黑屏 | 初始化顺序错误或请求动画帧循环未开始 | “请检查主循环是否在第一帧就调用了 update 和 draw,并确保背景填充覆盖整个画布” |
| 键盘无响应 | 监听了错误的按键码或事件未绑定 | “请改用 keydown 和 keyup 监听上下左右,并输出按键码到控制台方便调试” |
| 车辆直接冲出画面 | 缺少横向边界钳制逻辑 | “请为车辆添加 x 方向边界约束,让车辆不能越过两侧路肩” |
| 背景不滚动 | 滚动偏移变量没有随速度更新 | “请确保背景偏移量每帧都根据当前车辆速度叠加更新” |
| 锥桶碰撞不触发 | 碰撞判定阈值过小或对象引用错误 | “请把锥桶碰撞判定改为 AABB 包围盒检测,并输出碰撞日志” |
| 程序整体报错且模型反复失败 | 代码生成过程中引入语法错误 | “请检查完整的 HTML 代码,修正所有语法错误后输出完整文件” |
| 手机触摸无法操作 | 只写了键盘事件监听 | “请增加 touchstart 和 touchmove 事件,将触摸坐标映射为转向控制” |
这些修复指令的共同点,是告诉模型“你想看的结果”而不是“具体怎么改”,它自己会选择合适的实现方式。如果你不懂代码,也不需要懂,只需把现象描述清楚,模型给出的修改建议通常可以直接复制使用。
4.2 让模型自己修 bug 的调试技巧
很多人在这一步吃亏,是因为只丢一句“这游戏跑不起来”给模型。模型没有上下文,只能猜测哪里出了问题,输出自然是敷衍的替换整段代码。正确的提问方式要包含四个要素:报错原文、操作步骤、期望行为、相关代码片段。四者齐全,模型的修复成功率接近九成。
举个例子,你看到控制台报错ReferenceError: drawBackground is not defined,就直接把这段报错发给模型,加上“我打开页面按方向键时出现了这个错误,希望游戏正常绘制背景,请只修改相关部分”。模型会立刻定位到函数定义缺失或调用顺序错误,给出针对性补丁。
如果你使用的模型网页版支持上传代码文件,最省事的做法是把当前 HTML 整个上传,让它看完整文件后回答“基于这个文件怎么修复”。但要注意输出长度限制,如果文件太长,最好只把报错附近的关键函数贴进去,避免上下文被截断。
4.3 单文件小游戏的边界与取舍
AI 生成单文件小游戏的能力虽强,但不代表什么功能都可以硬塞进来。经过几轮测试,我明确知道以下三类功能在单文件模式里极容易翻车,建议量力而行。
第一类是外部资源加载。音乐、图片、字体如果要用<audio>或<img>引用本地文件,会导致单文件 HTML 不再自包含,打开文件时容易出现路径错误和跨域问题。模型对这种问题的处理通常不彻底。折中方案是让模型“用代码合成音效”,比如用 Web Audio API 生成一个短促的“叮”声,虽然音质朴素,却能保持单文件的纯粹性。
第二类是复杂的物理引擎交互。让模型在单文件里实现多辆车碰撞的详细刚体物理,输出代码很容易超出模型对 Canvas 游戏的典型认知范畴,出现各种不稳定的尖端情况。能用简单包围盒碰撞解决的问题,就不要让它硬写物理引擎。
第三类是依赖网络请求的功能。例如在线排行榜、登录系统、服务端存档,所有实时数据传输类功能都不适合纯前端单文件实现。如果非要加排行榜,我建议用 localStorage 存单机记录,等玩法稳定后再单独做后端服务对接。
4.4 真实踩坑记录:模型越自信,越要验证
有一次模型生成后表现得非常自信,代码注释也整整齐齐,结果我一打开,发现游戏里车辆一直斜着向左前方飞驰,完全不受控制。排查半天才发现问题的根源是模型把车辆的转向角度和位置更新绑在了一起,导致一旦按下方向键,车辆就会持续朝那个方向加速,而不是像预期那样只在按键期间转向。
我把这个现象发给模型,结果它认为自己没错,坚持输出一套解释。直到我明确指出“请检查 vx 是否只在按键期间更新,不要在按键结束后继续累加”,模型才意识到 bug 所在,给出了修正补丁。
这段经历让我养成一个习惯:不管模型说什么“已经修复”,我一定重新打开页面实测一遍。AI 生成的代码可以当成品来验收,但永远不能当结论来信任。
5. 扩展方向与个人体会
5.1 把生成的游戏变成可调参工具
模型在文件末尾留下的参数配置区,往后再看是我觉得最值钱的扩展点。我把这些配置变量挂载到window.gameConfig上,这样浏览器控制台可以直接输入gameConfig.maxSpeed = 20回车,立刻生效。这意味着你可以一边玩游戏,一边在控制台微调参数,实时感受手感和数值变化之间的关系。
此外我还会加一个config函数在游戏里生成简单的按键,比如按1切换调试模式,把帧率和车辆坐标显示在屏幕上。让模型做这个功能的指令非常简单,效果却非常香:快速定位碰撞、穿模、性能问题,全靠它。
5.2 我的真实体会
做了这个小项目,我最深的感觉是:AI 生成代码这件事,最怕的不是模型笨,而是我自己把需求描述得太模糊。一句“做个赛车游戏”得到的结果,和一段包含操作方式、功能清单、视觉风格、验收标准的提示词得到的结果,差距大到像两个不同水平的人写的代码。把提示词当需求文档来写,AI 才真正变成生产力工具。
另一个体会是,AI 写出的代码虽然能直接跑,但离“好产品”之间的差距通常不是 bug,而是细节。手感调校这种依赖主观感知的工作,机器很难一次给到最优解,它提供的是一个能快速迭代的初始版本,最终让游戏变好玩的思路和耐心,还是得靠人。加金币空气墙这类小功能,AI 三分钟就能实现,但怎么让赛道节奏有起有伏,必须自己一遍遍试玩才能有答案。
如果你看完文章也顺手生成了一款自己的小游戏,我建议从最简版本开始跑通,再逐步追加功能,这样模型每次只改一小块,出错的概率最低。等玩熟了这套流程,哪怕是完全没有编程基础的人,也能借助 AI 把脑子里的玩法念头快速变成屏幕里可以操作的原型。