ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

用Opus5.5从零构建赛车游戏:大模型真实开发能力实测

用Opus5.5从零构建赛车游戏:大模型真实开发能力实测 最近圈子里很热闹Opus5.5一出大家都在问它到底行不行。跑分刷了一堆各种基准测试拉满但说实话跑分这东西跟实际干活根本不是一回事。我自己的看法是与其看它在那堆标准化测试里翻跟头不如把它扔进一个真实的、有头有尾的项目里看看它在没有人全程喂饭的情况下能不能把一个东西从零搭起来。于是就有了这个想法让它做一个赛车游戏名字我都想好了“秋名山车神”。这篇文章就是这次“大考”的完整记录。我选了单文件HTML加Canvas加JavaScript的技术路线不碰任何框架不做任何预先设计逼着模型在纯前端环境下完成整个游戏。内容会覆盖我是怎么把一句“做赛车游戏”拆成可执行的需求怎么调提示词让模型产出工程化代码以及弯道物理、AI对手、DRS超车这些难点是怎么一步步磨出来的。如果你正准备拿大模型做点正经项目或者你好奇Opus5.5在真实开发场景里的表现这篇应该能给你一个挺直观的参考。1. 为什么选“赛车游戏”当考题需求拆解与产品定义先说清楚我为什么把考题定成赛车游戏而不是一个简单点的网页应用或者小工具。奥数考的是脑子但也不能只考脑子。一个赛车游戏要同时摆平的东西太多了实时渲染、动画循环、物理模拟、碰撞检测、输入控制、AI行为逻辑、UI状态管理。这些模块单独看都不难但放到一个页面里、在同一个循环里协调运行就是另一回事了。这跟真实项目很像——难点根本不在单个技术点而在模块之间怎么配合。我做这个游戏选的技术路线很保守单文件HTMLCanvas画布原生JavaScript加一点点CSS。没有React没有游戏引擎不引入第三方库。为什么这样选因为这是一个考察模型代码生成能力的理想边界。如果一个模型能在这种“一把梭”的约束下把游戏写完整那它在真实项目里让你少踩坑的能力就值得被认可。反过来如果它离开了框架就手忙脚乱那也要摸清它到底在什么范围内是靠谱的。定义产品规格之前我先问自己一个问题什么叫“秋名山车神”这五个字里有两个关键信息。一个来自地方标签“秋名山”——那意味着连续弯道、发夹弯、上下坡、窄路肩还有对走线的讲究。另一个是“车神”——这意味着玩家要能做漂移、时间要快、要跟AI对手拼超车要让人有“手感”这回事。把这种模糊感觉拆成可验收的功能点我列了一张需求清单车道能咬合一个连续弯道赛道布局至少包含S形弯、发夹弯和长直道三种典型路段。玩家赛车可以加速、刹车、转向且在弯道中维持一定速度时出现漂移感。至少两辆AI对手车它们要按赛道走线行驶不是傻乎乎的直线机器。实现一个简化的DRS机制贴近前车时获得额外加速用于完成超车。至少有一个有效的计时和圈数统计玩家知道自己是不是“车神”。单文件打开即玩没有外部资源。这个清单就是后续所有对话的基础。如果连这个都不写清楚直接丢给模型一句“帮我做个赛车游戏”它大概率给你一个看起来很漂亮、但完全跑不动或者手感稀碎的东西。这其实也说明了一个很关键的点跟大模型协作第一步从来不是让模型干活而是你自己先把需求想明白。你给它的不是一个指令而是一个可以落地的规格。2. 提示词工程把模糊想法翻译成模型能执行的规格我第一轮测试用的提示词非常简单原文差不多是“请做一个赛车游戏用HTML和JavaScript实现”。结果模型给了我一个能跑的Demo但整个项目有严重问题赛道是直的AI对手只会匀速画圈完全没有“秋名山”的味道。这个结果不能算失败但离目标差太远。问题出在哪模型接到的指令是一个模糊的愿望不是一个工程任务。于是我换了思路把提示词改造成了多维度的任务书。这里的关键不是把话说得多复杂而是要给模型一个完整的上下文边界。我最终用的提示词结构包含六段角色定义、项目目标、技术约束、功能清单、设计倾向、验收要求。下面是我直接给出的一段提示词你可以直接拿去参考你是资深前端游戏开发工程师擅长使用Canvas和原生JavaScript开发高性能2D游戏。 现在请你编写一个赛车游戏“秋名山车神”。技术栈仅限HTML、CSS、原生JavaScript不允许使用外部库或框架。 项目目标 1. 赛道为连续弯道的俯视视角山路包含至少两个S形弯和一个发夹弯。 2. 玩家控制赛车支持油门、刹车、左右转向。弯道中保持高速时要有侧滑和漂移感受。 3. 至少三辆AI车AI需要沿赛道合理走线速度会因弯道曲率而变化不会冲出赛道。 4. 实现简化版DRS玩家位于前车1.5秒内且处于直道时触发加速加成完成超车后失效。 5. 有圈速计时和当前圈数显示有“最快圈速”记录。 设计要求 - 操作手感优先转向响应及时速度曲线不要出现突兀跳动。 - 画面简洁配色克制不依赖图片资源全部用Canvas绘制。 - 代码结构清晰用类和函数拆分模块注释用中文说明关键逻辑。 验收要求 - 请先给出技术设计方案再一次性输出完整可运行的单文件代码。 - 代码中禁止写死玩家坐标为固定值所有碰撞检测基于几何计算。 - 生成结束后请附上运行说明和可能的调参提示。这次的效果完全不同。模型先给了技术方案然后输出了一段完整的单文件代码。我特别强调“先给技术方案再给代码”是为了逼它在动手前理清思路。这一步在做大模型辅助开发时极其重要因为模型在你的对话里是同步思考的。你让它先写方案它后面写代码时更容易保持逻辑一致而不是想到哪写到哪。提示词里还有一个值得说的点就是我把“手感”这种主观词做了量化尝试。什么叫“转向响应及时”我给了参数方向——不能出现速度曲线的突兀跳动。模型在代码里会体现为加速度的平滑插值而不是直接的数值跳变。大模型对形容词的理解很有限但对数字、逻辑约束和边界条件的理解要强得多。所以能在提示词里写清楚边界就一定别偷懒。3. 逐模块生成与集成从空页面到可玩的“秋名山车神”拿回第一版完整代码之后我做的第一件事不是验收而是把它跑起来看破坏性测试的结果。这一版大致能玩但问题也很明显赛道的弯道曲率是写死的玩家赛车碰撞边界有偏差AI车在发夹弯附近会不停地撞墙或飞出视野。如果把这些反馈直接丢给模型它的修复往往会引入新问题。所以我放弃了“一次生成、全局修复”的思路改成了分段迭代法。分段迭代法的逻辑很简单我按功能把游戏拆成五个轮次每一轮只让模型处理一个核心模块我负责把生成结果拼到已有项目里。第一轮是赛道生成要求它把弯道数据做成一段可配置的路点数组而不是直接画死。第二轮是玩家车辆与物理要求碰撞检测基于圆形包围盒转向时带一点横向滑动。第三轮是AI行为第四轮是DRS和UI第五轮才是整体打磨。这个过程中我会夹带一些自己写的代码作为固定框架。比如游戏主循环和车辆基类是我先写好的模型只负责往里面填具体逻辑。你可能会问既然都自己写了还让模型干什么答案是让模型把复杂但低创造性的部分高效完成比如赛道生成算法、AI线形插值、DRS状态机这种逻辑我提供接口和上下文它负责实现。人负责系统的整体架构和质量验收模型负责把局部做到位。下面这段是模型在第三轮生成AI对手走线逻辑时给我的核心代码我后来只做了少量参数改动。你可以感受一下它的处理方式class AICar extends Car { update(dt, track) { const targetIdx this.currentCheckpoint; const target track.checkpoints[targetIdx]; const angleToTarget Math.atan2(target.y - this.y, target.x - this.x); let steer angleToTarget - this.angle; while (steer Math.PI) steer - Math.PI * 2; while (steer -Math.PI) steer Math.PI * 2; this.steer Math.max(-1, Math.min(1, steer * 3.2)); const cornerAhead track.getCurvatureAhead(this.position, 120); this.speed Math.max(this.minSpeed, this.maxSpeed - cornerAhead * 320); this.accel (this.speed - this.speedKmh) * 2.1; } }这段代码的核心思路很简单AI车先锁定下一个检查点算出自己车头方向与目标方向的夹角通过一个增益值转成转向量再看前方120像素的赛道曲率曲率越大目标速度就越低。这个设计其实完全够用甚至比很多初学者自己写的“追点机器人”要好。为什么因为它同时包含了两层信息位置层面上的路径追踪以及速度层面上的过弯预判。这是“车神”感觉的底层来源。分段迭代最大的好处是问题可以被隔离。如果你一次性让模型生成一整块大功能渲染报错、物理失配、AI跑飞这些问题会搅在一起根本不知道是谁的问题。但每次只做一个模块我可以在集成时精准判断是模块内部逻辑不对还是接口没对齐。这样修起来非常快。整个游戏我从空文件到能完整跑完三圈一共花了两个晚上其中真正用于跟模型来回沟通的时间大约是六轮对话。4. 三大高难改造弯道物理、AI对手、DRS超车等到基础版本能跑了我开始上手加那三块真正能拉开档次的内容。这三个功能不是独立存在的它们共同决定了一款赛车游戏是“玩具”还是“有那么点意思”。第一个难点是弯道物理。很多做2D赛车游戏的人会把转弯做成一个简单的角度变化速度越快转得越急但这完全错了。真实赛车的过弯表现是速度与最大向心加速度之间的关系。模型给出的方案很聪明在主线路上预定义一系列路径点车辆在直道段沿y轴前进在弯道段根据路径点的曲率改变横向偏移。这意味着车辆从一个路径点向另一个路径点平滑插值而不是机械地转向。同时它引入了一个名为centripetalForce的参数用来限制过弯时的最大速度超过这个速度就开始侧滑。我后来把这个参数做了可视化发现曲线非常合理。玩家在弯道中如果速度过高会明显感到轮胎“抓不住”地面这就是手感的关键。这段是模型给出的弯道侧滑判定核心逻辑我基本原样保留const maxCornerSpeed Math.sqrt(centripetalForce * trackCurvatureRadius); if (this.speedKmh maxCornerSpeed) { this.drift Math.min(1, (this.speedKmh - maxCornerSpeed) / (maxCornerSpeed * 0.3)); this.sideOffset - this.drift * trackCurvatureDirection * dt * 0.4; }第二个难点是AI对手行为的差异化。三辆AI车如果用同一套逻辑跑起来就是复制粘贴一点竞技感都没有。我给模型提了个要求车手要有“性格”。模型的解法很巧妙——它把AI车分成三档标签激进型、平衡型、稳定型。激进型在弯道里更晚刹车速度上限高一点但容易在发夹弯失去路线稳定型更保守过弯精准但直道不占优势平衡型居中。它们在比赛中的实际表现差异非常明显激进型如果玩家不干预经常会在发夹弯冲出去这就是给玩家留的超车窗口。第三个难点是DRS减阻系统的简化实现。在真实F1里DRS是后翼减阻、降低空气阻力、在直道上获得额外速度的规则系统。在2D游戏里我不可能模拟完整的空气动力学所以我要求模型做一套状态机探测与前车距离如果小于一个阈值且当前处于直道段就激活DRS直道上的加速度提升约30%一旦玩家完成超车两车距离拉开超过阈值或进入弯道DRS关闭。这套机制的反馈非常清晰玩家会主动去贴前车的尾流然后在出弯的直道上突然发力这个是赛车游戏里最容易获得爽感的设计之一。DRS的核心状态切换逻辑是这样的const followingDistance this.distanceToNearestAhead(); const isOnStraight track.getCurvatureAhead(this.position, 100) 0.15; if (followingDistance 30 isOnStraight) { this.drsActive true; } else if (followingDistance 48 || !isOnStraight) { this.drsActive false; } if (this.drsActive) { this.acceleration * 1.3; }赛道地图我也不是随便画的。秋名山的核心特征是“五连发夹弯前的连续S形路段”和“最后一段长直道”。我让模型把这些元素按顺序编排成一个三圈制的赛道终点线设置在长直道末端这样既方便观赛也能让DRS在冲刺阶段频繁触发。模型给出的布局方案是赛道总长约2400像素其中弯道分布占比约55%直道占比约45%。这个比例我跑下来是舒服的既不至于全是弯道让玩家疲劳也不至于直道太多失去“山路”感觉。5. 模型能力边界与我的实测判断跑完整套流程以后我得说说Opus5.5的真实表现。先讲优秀的。第一它的完整文件生成能力明显强于前代。早期的模型你让它生成一个完整游戏拿到手十有八九是缺资源文件或者引用了不存在的API。这次生成的单文件HTML我在浏览器里直接打开就能跑没有缺标准库、没有外部依赖。第二跨模块一致性做得不错。它生成的代码里AI车的类和玩家车的类都正确继承了我预定义的Car基类方法名、属性名能对齐不会出现我让AI车调用一个根本不存在的方法的情况。第三它的自我解释能力帮助我迅速定位问题。当我问“为什么发夹弯中AI会冲出赛道”时它不是笼统地说可能代码有问题而是会指出具体是哪一行——某个参数在我改完玩家物理后没有同步更新到AI速度估算里。它能跨上下文找出隐含的数据依赖这个很关键。但边界也很明显。第一个问题是长对话后期的“约束遗忘”。我在前两轮里明确要求赛道宽度统一为40像素但在第七轮让它加一个观众席装饰时它重画赛道边界把宽度改成了52像素导致碰撞检测全部失效。这属于长上下文里的典型问题。解决办法也简单每次让它修改重要模块时我都把相关约束重新贴在对话开头。模型不会主动记住你的历史边界你要负责“循环提醒”。第二个问题是它对“手感”的理解依然有限。它能理解什么是平滑、什么是响应迅速但它不知道什么样的转弯力度算“舒服”。我给它的转向参数范围是0.5到2.0它默认选了1.2跑起来偏飘。我试了0.8和1.0最终选了0.9。这种参数校准工作模型没法替你完成必须靠你亲手跑、亲手试。任何告诉你“直接把手感交给大模型调就行”的说法都是不现实的。第三个问题是它会产出“看似合理实则错误”的物理参数。比如它在DRS加速阶段直接把加速度乘了1.3看起来没问题但实际跑起来会发现玩家在直道末端速度达到380km/h远远超出赛道物理的承受范围导致转向反应丧失。这个问题的根源是模型的物理计算没有做“全局一致性校验”。它解决局部问题时不会回头检查对全局数据的影响。所以每轮修改后我都需要自己跑两圈观察数值上限是否合理。我还做了一个简单的成功率统计一共让模型生成了六次完整版本其中两次可以称为“开箱即玩”没有明显bug三次存在一个需要手动修的参数问题一次因为赛道布局不合理导致碰撞检测失效得重做。这个结果比我预期的好。但不管哪种情况人工验收环节一步都不能省。模型写出来的代码你是要负责上线运行的你为它兜底的能力才是项目能不能成的关键。6. 给准备“拷问”大模型的人几条建议如果你也要拿大模型做这种半娱乐半实战的项目我这几天攒下来的几条建议应该能帮你少走点弯路。第一把大模型当作一个能力很强的实习生而不是一个自动写码机。实习生的特点是给他一个明确的小任务他能干得很漂亮让他负责一个大项目他会东一榔头西一棒槌。所以你作为主导者重要的是拆任务、给边界、做验收。哪怕是一次小小的“添加一个暂停按钮”也要说清楚它应该挂在哪个事件上、聊不聊UI样式、还是保持默认风格。第二使用“分段迭代代码合并”而不是“一句话生成整个游戏”。我在前面已经反复强调了这个策略。这样做最大的好处是问题可以被隔离到单一模块里修起来成本低得多。同时中途集成也让模型有机会处理真实接口而不是空想接口。第三把模糊的概念翻译成可量化的数值指标。对模型说“这个车太飘了”没有用你要说“速度超过220km/h时转向增益需要从1.2降到0.8同时漂移系数从0.6调整为0.4”。模型不能理解你的感觉但它能精准执行你给的数值。这种“感觉→数值”的翻译能力才是你在这类项目里真正的竞争力。第四主动让模型给自己写测试用例。我最后让模型生成了一个自检逻辑在无输入情况下AI完成五圈统计冲出赛道次数和平均单圈时间。这个测试跑完模型的AI逻辑是否合格一目了然。一个好的提示词不仅要求功能还应该要求可验证性。最后说一个我个人的体会。你可能会觉得这篇文章到最后也没给你一个“完整游戏代码”而是给了很多思路和片段。我是故意的。大模型时代最不缺的就是代码缺的是做判断的经验和方法。代码只是结果而怎么把一个模糊想法翻译成能让模型执行的清晰指令怎么在它出错时快速定位、精准修正这些才是真正值钱的东西。拿Opus5.5做这个游戏这几天我最大的收获不是“秋名山车神”跑通了而是我确认了一件事模型负责快你负责稳。只有人机配合到位才叫真正会用大模型做项目。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进