AI辅助编程实战:从零开发HTML5赛车游戏全程记录

发布时间:2026/10/7 18:26:07
AI辅助编程实战:从零开发HTML5赛车游戏全程记录 赛车游戏大概是所有游戏类型里最“考验编程功底”的种类之一。它表面上看只是一辆车在跑但背后牵扯物理模拟、碰撞检测、AI追踪、渲染性能、输入手感一堆问题。这次我拿 Opus5.5 当主力开发工具从零开始做一个叫“秋名山车神”的网页赛车游戏目标很明确看看它能不能在我只给需求、不给现成代码的情况下把一个完整可玩的游戏一步步搭出来。项目最终落地成纯前端 HTML5 Canvas 游戏支持键盘操作、漂移手感、三辆AI对手车和一套多弯道赛道。这篇博客把整个大考过程、踩过的坑、打磨细节全部摊开写想用 AI 辅助做小游戏或者对赛车游戏开发感兴趣的读者应该都能从中拿走点东西。1. 为什么拿赛车游戏当考题1.1 赛车游戏的难度梯度很合适做游戏评测 AI 编程能力这件事最怕选错项目。如果只做一个“点击按钮得分”的小游戏那测出来的只是 AI 拼接模板的能力没太大说服力。但如果一上来就做 3D 大作又脱离实际几分钟生成一堆炫技代码也未必能跑。赛车游戏刚好卡在一个完美的中间档位。2D 俯视角赛车游戏看起来简单实际踩一下需求就会发现它横跨了好几个独立的技术模块车辆物理模型加速度、摩擦系数、转向速率的平衡直接决定手感好不好。漂移机制需要额外设计侧滑、抓地力衰减、恢复对齐的逻辑这是区分“玩具车”和“赛车游戏”的关键。碰撞系统车撞墙不能直接穿模要有速度损失和方向反弹。AI 对手对手车要能自己沿着赛道跑还要会超车或者被玩家挡住不能像个橡皮筋一样永远贴着玩家。赛道设计弯道、直道的节奏编排以及终点线判定。游戏循环与窗口管理状态机菜单、游戏、结算、计圈计时、键盘监听。这些模块单独拆出来都不算难但组合在一起就是一个不错的压力测试。我想看的关键点是AI 能不能在理解整体需求的基础上给出层次清晰的项目结构而不是把所有代码堆在一个 index.html 里改起来让人崩溃。这个点上这次 Opus5.5 的表现确实值得聊一聊。1.2 技术选型为什么是 Canvas 而不是 Three.js游戏开发路线其实有好几条纯 DOM 加 CSS 动画、Canvas 2D、Three.js 做 3D甚至直接用游戏引擎。这里有个很重要的取舍逻辑。用 Three.js 听起来更酷但代价是引入了三维数学、相机控制、光照阴影一堆额外复杂度。对一个小型测试项目来说每多一层复杂度AI 生成代码的出错概率就会成倍上升。纯 DOM 方案则反过来能力上限太低连基本的 60 帧平滑移动都要靠 CSS transform 硬撑物理碰撞做起来非常别扭。Canvas 2D 是那个“刚刚好”的选择。它自带绘图上下文可以逐帧绘制天然适合游戏循环碰撞检测直接用坐标运算就行浏览器兼容性也几乎没有坑。最终整个项目就是一个 index.html 加一个 game.js所有资源靠代码绘制连图片素材都省了。这还有一个额外好处整个项目可以完整拷给别人直接跑不需要任何构建工具。给后来者一个建议用 AI 做游戏项目时第一轮对话先别急着谈功能先把“用什么技术栈”这件事聊明白。技术栈决定了后续所有代码的结构一旦中途想换等于全部推倒重来。2. 核心机制设计拆解2.1 车辆物理模型手感是调出来的不是写出来的赛车游戏最灵魂的部分是手感。手感说白了就是车辆对输入的响应曲线它由一套物理参数决定。我一开始给 Opus5.5 的需求很简单“一辆能加速、能刹车、能转弯、转弯半径随速度变化的车。”它第一次给出的代码确实能跑但开起来像在冰面上滑冰——转向过度、刹车距离不真实、速度感缺失。问题出在它的初始物理模型太粗糙。后来我们一起把模型改成分层结构每个时间步先处理加速度与刹车再施加摩擦阻力最后根据当前速度计算转向角度变化。核心逻辑大致长这样const car { x: 400, y: 300, angle: 0, speed: 0, maxSpeed: 320, acceleration: 180, brakeForce: 260, friction: 0.985, turnSpeed: 3.2 }; function updateCar(dt, input) { // 第一层纵向加减速 if (input.up) car.speed car.acceleration * dt; if (input.down) car.speed - car.brakeForce * dt; if (!input.up !input.down) car.speed * 0.96; // 第二层速度上限与自然阻力 car.speed Math.max(-car.maxSpeed * 0.4, Math.min(car.maxSpeed, car.speed)); car.speed * Math.pow(car.friction, dt * 60); // 第三层转向速度越高转向增益越低 const speedRatio Math.abs(car.speed) / car.maxSpeed; const turnFactor 1 - speedRatio * 0.65; const direction car.speed 0 ? 1 : -1; if (input.left) car.angle - car.turnSpeed * turnFactor * dt * direction; if (input.right) car.angle car.turnSpeed * turnFactor * dt * direction; // 第四层位移 car.x Math.cos(car.angle) * car.speed * dt; car.y Math.sin(car.angle) * car.speed * dt; }这里最关键的调校点是turnFactor。如果不加这个系数车在高速时打方向会瞬间转 90 度完全脱离物理直觉。加了这个速度相关的转向衰减后高速时方向变得“重”低速时变得“灵”这正好符合真实赛车的转向特性。我还特意加入了倒车逻辑——按刹车键可以让车减速到零然后向后移动。这块 AI 一开始没考虑到因为它的训练数据里很多赛车游戏不做倒车。但实际玩起来“卡墙后倒车脱困”是这类游戏的高频操作必须有。2.2 漂移机制把“失控”变成“可控”漂移是“秋名山车神”这个名字的题眼。做标题党容易但真要做出有感觉的漂移需要在物理模型里额外加一个“侧滑角”的概念。我的实现思路是维护一个当前朝向角angle和一个实际速度方向角velocityAngle。正常行驶时两者相同当玩家高速入弯并打方向时两个角开始分离车辆进入侧滑状态。侧滑过程中如果玩家持续打方向车辆会维持一个小角度的可控滑行如果玩家松油门或反打方向侧滑逐渐收敛回抓地状态。let driftAngle 0; // 侧滑角单位弧度 function updateDrift(dt, input) { const speed Math.abs(car.speed); const lateralThreshold car.maxSpeed * 0.45; if (speed lateralThreshold input.left) { // 入弯产生侧滑 driftAngle Math.max(driftAngle - 1.8 * dt, -0.35); } else if (speed lateralThreshold input.right) { driftAngle Math.min(driftAngle 1.8 * dt, 0.35); } else { // 滑行中慢慢回正 driftAngle * Math.pow(0.15, dt); } // 实际移动方向 车头方向 侧滑角 const moveAngle car.angle driftAngle; car.x Math.cos(moveAngle) * car.speed * dt; car.y Math.sin(moveAngle) * car.speed * dt; }这套简化模型跟真实的“漂移物理”当然有差距但对网页游戏来说已经足够。关键点是侧滑角的上下限要压住——如果允许无限侧滑车会直接变成陀螺。我最后把上限设在 ±0.35 弧度约 20 度视觉上能明显看到车头指向和行进方向不一致但又不会完全失控。新手容易踩的坑为了让漂移“看起来明显”把侧滑角调得很大结果玩家根本没法控制方向。我的经验是漂移手感要“看得出、控得住”宁可保守一点也不要让体验变成碰碰车。2.3 赛道与计时弯道才是灵魂赛道是一圈闭环路线。我这里没有用复杂的图片素材而是用一个路径点数组定义赛道的中心线然后由中心线向两侧扩展生成路肩线。这样做的最大好处是改赛道就是改几个坐标点的事调试迭代极快。const trackPath [ { x: 400, y: 720 }, { x: 420, y: 560 }, { x: 520, y: 480 }, { x: 620, y: 380 }, { x: 540, y: 260 }, { x: 350, y: 200 }, { x: 210, y: 320 }, { x: 260, y: 480 }, { x: 180, y: 600 }, { x: 280, y: 680 } ];之所以叫“秋名山”是因为我在赛道的后半段安排了一个连续 S 型弯道模拟秋名山上著名的那几个连续发卡弯的节奏感。连续弯和单弯的体验差别很大单弯玩家只要会减速就能过连续弯则需要提前规划行车线否则在第二个弯必定撞墙。这个设计极大提升了游戏的可玩性。计圈逻辑也不能马虎。玩家跑完一圈回到起点线时要判断“是否真的跑满了一圈”而不是反向冲线也算。我设计了检查点系统起点线的前后各设一个隐形触发器只有按顺序通过前半程检查点再压到终点线才判定一圈完成。这个逻辑排除了抄近路、反向绕圈的作弊情况。AI 对手的路径追踪相对简单每辆 AI 车都沿预设的目标点序列行驶目标点会按距离自动切换。AI 车同样受物理参数约束所以它们在弯道会自然减速不会出现鬼畜的瞬移。玩家撞到 AI 车时两车都会减速这算是个简单的碰撞反馈。3. Opus5.5 实操过程全记录3.1 第一轮对话把大目标拆成小任务跟 AI 协作写游戏最忌讳的是在第一句话里就要求“帮我做一个完整的赛车游戏”。Opus5.5 确实能理解这个请求但它给出的代码必然是模板化的什么都有什么都不精。我的做法是先把它当成一个架构师第一轮只谈拆分第一轮我的 Prompt 大致是这样的“我要写一个 HTML5 Canvas 赛车游戏请先帮我规划项目结构和文件清单包括需要的模块物理、渲染、AI、UI、关卡和每个模块的职责。”这次输出非常务实它给了一个我可以直接照做的分层结构而不是一上来甩代码。第二步才开始逐模块生成。顺序上我刻意选了“先物理、再渲染、后 AI 对手、最后 UI 包装”。原因是物理模型是手感的地基而渲染只是把物理状态画出来AI 又依赖物理模型才能动。这种依赖顺序可以最大程度减少返工。3.2 迭代过程中的关键 Prompt 技巧在调漂移手感那一段我体会最深的是一个很实用的技巧给 AI 提供“可量化的失败反馈”而不是笼统地抱怨“手感不对”。第一次试玩时车速到一半入弯车尾甩得太夸张几乎没法控制。我原来会写“漂移太严重了改一下”但 Opus5.5 听到这句话最多把侧滑角阈值改大一点问题依然存在。后来我换成这种描述当前漂移在车速 220 时侧滑角达到了 0.5 弧度持续 2 秒都无法回正玩家反馈失控。请把侧滑角上限限制在 0.3 弧度以内并让松油门后的回正速度提高 3 倍。这一下就精准了。因为 AI 能直接把飘移收敛的目标参数算出来而不是靠猜。经过两三轮这样的调整漂移手感基本就到位了。这也印证了一个观点和 AI 协作写代码本质上是在做“需求澄清”你给出的反馈颗粒度越细AI 的修正就越准。另外一个实用技巧是每次修改前先用中文注释把意图说明再请它改写代码。比如我要求“给碰撞系统增加一个冷却时间防止车辆在撞墙后的一帧内反复触发速度损失”它生成的代码里就会明确体现这个意图而不是默默改一个我们都没发现有问题的魔法数字。3.3 代码生成之外的边界不是所有事都适合交给 AI这次测试里我也刻意留了几个不该让 AI 拍板的决策点。一个典型例子是赛道坐标我可以让 AI 随机生成一堆坐标点但它生成的是“几何上合理的坐标”不是“有驾驶趣味的赛道”。赛道布局本质上是个设计问题需要人对驾驶节奏有体感。我最后是自己手调了几版坐标手感立刻不一样。另一个例子是音效。这次项目本来不打算加声音但试玩后总觉得缺少点速度感。用 AI 生成一个小段 WebAudio 引擎轰鸣声其实可行——用振荡器加噪声源模拟发动机转速变化。但这个部分效果一般因为在浏览器里模拟真实声学还是太难最后干脆把音量调低做成背景白噪声式的存在。我的结论是视觉和手感可以放心让 AI 来写但设计与审美的决策还是要人来做最终判断。4. 踩坑实录与排查技巧4.1 Bug 榜单跑着跑着车就“飞”了连续几天密集测试下来遇到的 Bug 不少但其中几个特别有代表性。第一个是“车辆穿墙飞出去”。原因是碰撞检测里用了car.speed作为穿透判断的依据但是物理更新和碰撞检测的顺序不对——先移动后检测高速时一帧移动了 5 个像素直接跨过了墙的厚度等到检测时已经穿模了一半。解决方式有两种要么把碰撞检测放在物理移动之前要么在检测到穿模后把位置回退。我最后采用了“碰撞前位置快照”的方案每一帧更新前保存上一帧的坐标一旦检测到碰撞就把车辆坐标恢复为快照同时把速度乘以 -0.3 实现反弹。这个方案稳定也没有额外性能开销。第二个典型 Bug 是 AI 车在玩家旁边时疯狂抖动。排查后发现AI 的目标点切换逻辑每帧都重新计算最近点而玩家车挡住 AI 车后AI 的目标点会在两个相邻检查点间来回跳造成蛇形抖动。修复方法很简单预测目标点的切换加上 hysteresis 滞回区间也就是“新的目标点必须比当前目标点近超过 30 像素才切换到新点”。加了这层滞后AI 车立刻稳了。第三个是计圈逻辑错乱。玩家倒车冲过起点线也被算成一圈。这个靠前面提到的检查点序列解决了记录玩家最近通过的检查点编号终点线只有在“上一个检查点已经通过”的前提下才触发计圈。4.2 性能瓶颈排查帧率掉到 30 的真相上线后最大的问题不是 Bug而是帧率。低配电脑上 30 帧都稳不住。一开始我怀疑是碰撞检测太慢但用 Chrome 的 Performance 面板一测发现真正的大头其实是填充操作我给弯道两侧画了很宽的绿色草地边框用的是一帧一帧绘制大量圆角矩形路径。在低性能设备上每帧 GPU 都要重绘整个背景这是浪费。优化思路也不复杂把静态背景草地、路肩、终点线预先绘制到离屏 Canvas 上只在游戏初始化时画一次之后每帧只需把离屏 Canvas 用drawImage整体贴上去再单独绘制动态的车辆和漂移痕迹。这一步操作直接让帧率从 30 出头提到了满帧 60。漂移痕迹则是用一个数组保存最近 60 帧的车轮位置每帧画几条不透明度递减的短线成本极低。5. 打磨细节与发布心得5.1 小地图、氮气加速与“车神”彩蛋赛车游戏不能只有竞速本身外围系统决定耐玩度。我给游戏加了一个小地图把赛道中心线缩放到左上角实时画一个小白点表示玩家位置。这个功能对初玩者特别有用因为连续 S 弯很容易让玩家跑错方向小地图能快速定位自己处在哪个弯道。氮气加速是后来加的。设计逻辑是漂移时积攒氮气值漂移距离越长氮气槽涨得越快松开漂移后按 Shift 键可以消耗氮气获得短时加速。这个机制反过来激励玩家主动去漂移形成了“越飘逸越快”的正向循环。秋名山车神的彩蛋设在第一名的名字里如果你跑完全程拿到第一结算画面会显示“今晚秋名山车神就是你”。这种小彩蛋花不了多少代码量但每次跑完第一看到这句话成就感完全不一样。5.2 发布与后续扩展建议游戏是纯前端项目发布几乎没有门槛。把 index.html 和 game.js 上传到任意静态托管平台就能玩。我最后是打包压成了一个单文件 HTML因为把所有 JavaScript 内联之后单文件在任何地方打开都能运行分享给朋友体验最省事。后续如果要继续扩展方向大概有三种一是增加赛道编辑器让玩家自己画路线二是接入联机对战需要 WebSocket 服务端同步车辆状态三是把 AI 车改成基于行为树的策略让对手车学会堵路和被超车后反击。这些扩展中赛道编辑器是最值得先做的——它成本低、玩法增量巨大而且很适合继续用 AI 辅助开发。最后说点个人的真实体会用 Opus5.5 做这个项目的整个过程让我最意外的不是它“能写代码”——很多模型都能写代码——而是它在理解“为什么这么改”这件事上的表现。当我把失败反馈量化给它它给出的修改方案往往能落在正确的物理参数上而不是机械地堆代码。这种协作模式下开发节奏从“写代码”变成了“提需求和审代码”省下来的时间大部分都花在了试玩和调手感上。对于想快速做游戏原型的人来说这条路完全走得通。至于那句“秋名山车神”我建议你别只当个标题看——认真漂几个圈亲手拿一次第一你会懂这个名字的含金量。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询