AtomGit华为云码道CodeArts纯HTML复刻经典Battle City并自动AtomGit仓库一键发布的AIGC开发全记录
一键开通华为云码道 CodeArts 代码智能体https://developer.huaweicloud.com/codeartsco.html?sourcedmzntgwatomgit1sourceaddmzntgwatomgithd周末想找点事做。不是那种打开编辑器、新建文件夹、然后对着空白 main 函数发呆的事而是想快点摸到一个能玩的东西。选来选去题目定在了坦克大战上——Battle City红白机时代的经典规则一句话能说完开坦克打敌人护基地。规则简单但骨架不缺要地图、要碰撞、要敌人 AI、要道具、要状态机麻雀虽小五脏俱全正适合拿来做一个“简单的游戏功能”。这次我依旧没有自己动手写而是把想法整个丢给了 AtomGit 网页端的华为云码道 CodeArts模型选的是 deepseek-v4-fla 那一档。我的第一句话也很糙“帮我开发一个坦克大战的游戏需要纯html的”。没有规格说明没有 PRD没有线框图。接下来发生的事情从技能匹配、地图字符画、滑墙算法到浏览器自动化验证十三条逻辑路径再到最后仓库推上 AtomGit我把整个会话的截图都留了下来这篇文章就按真实发生的顺序往回捋。一、提示词落地先判断“要不要用技能”再回答“怎么做”提示词发出去之后CodeArts 没有急着写代码第一件事是自我审视。深度思考里写得很直白用户想要坦克大战纯 HTML这是一个创建新功能的创造性工作按照规则应该先检查是不是有既有的技能可以驾驭——坦克大战属于“经典游戏类型”纯 HTML需求相对清晰不需要太多头脑风暴直接调用 game-maker 技能。中间还有一段小插曲值得记录。系统里有另一个 brainstorming 技能标注是“You MUST use this before any creative work”听起来任何创造性工作都得先过它一遍。但 CodeArts 自己做了权衡这属于经典游戏类型需求相对清晰再加上用户意图回归明确——坦克大战经典游戏类型纯 HTML需求相对清晰不需要太多头脑风暴。于是跳过了 brainstorming直接挂载 game-maker。这个判断本身就很有意思技能系统给了它一个“强制”约束它根据上下文判断这个强制不适用于当前场景并且把理由写在了思考链里。换成新手大概率是规则写了什么就照做什么或者干脆无视规则。game-maker 技能被调用后输出了一份技能内容开头是角色定位“你是具备十年游戏开发经验的专业游戏架构师擅长将用户的抽象游戏想法转化为具体可执行的游戏设计文档。” 紧跟着是所有游戏必须遵循的状态机定义IDLE --start-- PLAYING PLAYING --gameover-- GAMEOVER GAMEOVER --restart-- IDLE还有一份游戏设计文档GDD模板把核心循环抽象成了一行伪代码while (gameRunning) { 处理输入 → 更新状态 → 检测碰撞 → 渲染画面 → 播放反馈 }这两段模板看着朴素实际上是这次开发全程的骨架。后面写出来的坦克大战确实就是按这个状态机和这个主循环长的。二、查家底技能库里没有坦克模板那就自己写技能挂载完CodeArts 干的第一件实事不是写代码而是查家底——先看看技能目录里有没有现成的生成脚本或模板可以参考ls -la /root/.codeartsdoer/skills/game-maker/scripts/ 2/dev/null输出挺丰富breakout_game.py、snake_game.py、tetris_game.py、three_d_maze.py、three_d_flappy.py、three_d_platform.py、three_d_racing.py、three_d_scene.py、three_d_shooter.py、three_d_sphere.py……两百余 KB 的脚本库覆盖了打砖块、贪吃蛇、俄罗斯方块和一票 3D 小游戏唯独没有坦克大战。CodeArts 的结论也很干脆“没有坦克大战的现成脚本我需要直接编写一个坦克大战游戏。” 它顺带把坦克大战的最小要素列了出来玩家坦克方向键/WASD 移动加空格射击、敌方坦克 AI 自动移动和射击、地图砖墙钢墙障碍、护基地、消灭所有敌人过关。然后又查了一层 references 目录找到三份参考文档ARCHITECTURE.md、game-dev-guide.md、game-template-lists.md确认工作目录是空的、没有坦克模板于是建了一条 TODO 列表编写坦克大战游戏 HTML 文件、验证游戏可运行。任务面板上挂着两条“编写坦克大战游戏地图/玩家/敌人AI/子弹/道具/音效/状态机全部闭环”、“本地启动服务并用浏览器验证游戏可运行、无报错”。这一段是我整场会话里觉得最“工程化”的部分。新手拿到“做个坦克大战”的需求通常直接开写写完再想测试的事CodeArts 的路径是先查复用资产、确认没有、再规划任务、然后才动笔。复用优先兜底手写这个顺序值得每个开发者记在心里。三、设计深潜一张 13x13 的字符地图和一堆自己回答自己的问题真正开始写之前CodeArts 用了大量篇幅做设计推演而且是以“自问自答”的方式进行的。这一段的长读截图信息密度极高我挑重点说。地图与渲染。地图用 13x13 网格经典布局每个 tile 40 像素画布 520x520。地图直接用字符表示S 是钢墙、B 是砖墙、M 是水、T 是树、. 是空地、G 是基地。它先画了一张示意图然后逐行检查字符数——13x13每行必须 13 个字符还专门数了 Level 1 里砖块的数量。这种“先把数据定死再写逻辑”的做法后面省了不少调试时间。碰撞检测。坦克是 40x40 的正方形与地图 tile 产生碰撞时阻止移动。它注意到坦克边缘不一定对齐网格采用四角采样的方式分别检测检查坦克中心点以及坦克四角是否进入墙 tile。子弹同理命中砖块就消除一个 tile或削弱砖块耐久命中钢墙产生火花。移动的细节滑墙。这是我觉得全场最见功力的一处。它没有把移动做成“撞墙就完全卡死”而是分轴处理functiontryMove(tank,nx,ny){// nx, ny 新位置左上角屏幕坐标// 先检查 x 方向if(nx!t.x){constcxnx;if(!collides(t,cx,t.y)){t.xcx;}}if(ny!t.y){if(!collides(t,t.x,ny)){t.yny;}}}x 和 y 两个方向分别尝试、分别放行这样玩家贴着墙移动时会顺着墙面滑过去而不是被一个角卡住整个身位。玩过老式坦克游戏的人都知道滑墙手感直接决定这个游戏“像不像”坦克大战。一个看似不起眼的函数把经典手感复刻出来了。敌人与平衡。敌人最多同时 4 个经典设定总共 20 个分四种类型重甲坦克 power 2-3、armor 4 次击毁。敌人被消灭时按 15% 概率掉落道具。敌人 AI 会朝基地推进也会追击玩家。玩家出生点带保护3 条命。道具系统。六种道具它用一张常量表定死constPOWERUP{STAR:0,// 火力升级GRENADE:1,// 消灭场上敌人SHIELD:2,// 护盾TANK:3,// 加命SHOVEL:4,// 基地钢化墙CLOCK:5// 敌人暂停};每个道具的效果也在推演里逐条写清星星累积升级火力最多 4 级、手雷消灭场上敌人并按敌人类型给分、铲子把基地周围砖墙临时换成钢墙 15 秒后恢复、时钟让敌人暂停 8 秒、坦克加命、护盾反弹子弹。音效不引外部资源全部用 Web Audio API 现场合成。关卡。设计了 2 张不同的地图通关后进入下一关。它甚至在思考里逐字符核对两张地图的布局、基地位置col11, row12和玩家出生点col1, row11确认出生点周围是空地、不会和基地重叠。整段设计推演下来最大的感受是它把一个新手会在编码阶段反复返工的问题全部前置到了设计阶段解决。地图多大tile 几个像素碰撞怎么采样道具掉率多少护盾持续多久每一个都有明确数值。代码只是把这些决定誊写一遍。四、代码落盘一个文件八百到一千行设计定案后CodeArts 开始写完整代码文件。它给自己的约束很具体页面控制说明WASD/方向键移动、空格射击、P 暂停、Enter 开始、代码控制在 900~1100 行、尽量保持在 800 行内、字体用像素风 canvas fillText、音效全合成、无外部图片资源。渲染部分坦克不是贴图而是纯 Canvas 绘制。drawTank 函数把坦克拆成履带、履带纹、车身、炮塔、炮管几层逐个 fillRectfunctiondrawTank(t){ctx.save();ctx.translate(t.xTANK_SIZE/2,t.yTANK_SIZE/2);ctx.rotate(t.dir*Math.PI/2);ctx.translate(-TANK_SIZE/2,-TANK_SIZE/2);// 履带ctx.fillStylet.trackColor;ctx.fillRect(0,4,TANK_SIZE,10);ctx.fillRect(0,26,TANK_SIZE,10);// 履带纹for(leti2;iTANK_SIZE;i7){ctx.fillRect(i,5,4,8);ctx.fillRect(i,27,4,8);}// 车身 / 炮塔 / 炮管 / 护盾光环 ...}旋转用 ctx.rotate 加 Math.PI/2 的倍数实现四方向护盾存在时还画一圈闪烁描边。整个游戏最终写进 /workspace/tank_battle.html 这一个文件Write 工具返回 “Wrote file successfully”一次成型。五、验证闭环从 node 语法检查到浏览器实测中间还有一次漂亮的降级代码写完好戏才到一半。CodeArts 的验证路径分了好几层每层都值得展开讲。第一层语法检查。先把 HTML 里的 script 提取出来做语法验证。它用的命令很朴素python3 一行脚本提取 JS输出 “extracted 29855 chars, JS语法OK”。这个数字后面还反复出现——29855 个字符的 JS纯手写也就这个量级的十几分之一。第二层浏览器自动化——这里有全场最漂亮的一次降级决策。它先尝试用 Playwright 打开页面结果 Python 环境报 ModuleNotFoundError: No module named ‘playwright’。它没有硬装、也没有就此跳过浏览器验证而是在深度思考里写明“Python 没有 playwright但系统有 puppeteer-core 全局模块和 chromium-1243 缓存我可以写一个 Node 脚本使用 puppeteer-core 连接 chromium 测试浏览器。” 然后用 find 定位浏览器二进制/root/.cache/ms-playwright/chromium-1243/chrome-linux/chrome /opt/cloud/devtools/nodejs/v22/lib/node_modules/puppeteer-core/lib/cjs/puppeteer/...接着写了一个 puppeteer-core 验证脚本连上系统里现成的 chromium 跑真浏览器测试。工具坏了就换工具验证标准不降级——这是 AIGC 开发里最容易被忽略、也最值钱的能力。第三层截图与错误排查。脚本在 /tmp 下生成了三张截图idle、playing、action 三个阶段CodeArts 检查后确认找到的唯一错误是 favicon 404——浏览器自动请求 favicon非游戏问题。它顺手在 head 里加了一行link relicon hrefdata:,消掉这个噪音并说明这不是游戏逻辑问题。把“无害错误”和“真错误”分开不做无谓的返工也是一种判断力。第四层长时游戏逻辑验证。加长测试到 30 秒验证玩家能击杀敌人、获得分数、且 30 秒后游戏仍在进行平衡性检查。脚本持续轮询 HUD 状态{state:PLAYING,score:0,enemies:20,lives:3,playerHp:1,enemyCount:...}结论未检测到 GAMEOVER游戏正常持续、NO JS ERRORS。它还顺带做了一段平衡性分析玩家出生有 260 帧约 4.3 秒护盾加出生点保护敌人出生点距离玩家较远30 秒时基地安然无恙数值是成立的。第五层逻辑路径全覆盖。这是整个验证阶段的高潮。CodeArts 列出了一张 13 条逻辑路径的验证清单每一条都标注了实测结果初始护甲lives3, hp0重生计时启动 ✓命重生hp1, lives2 ✓连续死亡至 GAMEOVERlives4→重置开gameover 正常✓Enter 重开 → 回到 PLAYING, lives3, score0 ✓清空敌人 → LEVELCLEAR → 自动进入第 2 关level“2”✓第 2 关通过 → VICTORY ✓重启后 Enter 重开 → 第 1 关 PLAYING ✓STAR 道具power 0→1, bulletsMax 1→2 ✓其他power2 ✓TANK 道具lives1 ✓SHIELDshield0 ✓CLOCKclockTimer480 ✓GRENADE敌人 3→0 ✓SHOVEL加固场景level2 布局无砖差异此处 baseWalls2 与 Level1 分析一致两块砖(10,10) 和 (10,12)✓全部逻辑路径验证通过无 JS 错误。中间还发现一条“第 2 次空降敌人 undefined”的闪现它排查后确认只是函数只设置不返回、不影响任何状态随后做了最终完整验证组收尾。把每一条分支都当测试用例跑一遍、把无害异常也解释清楚这种验证密度人类新手在一次周末小项目里基本不会做到。六、“功能完成了吗”一次成本数据摆在上面的交付确认验证跑完用户问了一句“功能完成了吗”。CodeArts 的回答简洁但信息量很足核心内容如下——核心玩法坦克移动/射击、4 种敌人 AI、砖墙/钢墙/水/树地图、基地攻防完整闭环开始界面 → 战斗 → 第 1 关生命耗尽4 命→ GAMEOVER/重玩 → 通关第 2 关 → VICTORY6 种道具星、弹药、护盾、加命、铲子、时钟均已实测生效表现层粒子爆炸、火花特效、像素风渲染、音效、HUD、暂停、移动端触屏全部逻辑用浏览器自动化验证过无 JS 错误。文件在 /workspace/tank_battle.html直接双击打开即可。回答末尾还有一行成本数据耗时 13.1 秒、缓存命中 68%、输入 52.1k tok、输出 1941 tok。想补充更多关卡、双人模式、音效增强、排行榜一句话即可。对新手来说这一段的价值在于交付的“形状”不是一个 HTML 文件甩过来完事而是功能清单、验证方式、文件位置、后续扩展方向一次说清。交付物的边界感是工程能力的一部分。七、建仓发布先认证、再弹窗确认、最后 API 修正可见性功能确认后用户补了一句“帮我初始化到atomgit仓库中并且丰富一下reamd文档。” CodeArts 的深度思考把这件事拆成了五步检查 ag-cli 技能、检查认证状态、写丰富 README、git init 加提交、在 AtomGit 创建仓库并推送。并行检查技能与 bash 状态后加载了 ag-cli 技能然后which ag ag auth status # /usr/local/bin/ag # Logged in to atomgit.com as guowei88认证没问题但创建仓库前需要确认参数。这里出现了和前几次实践里同款但更成熟的交互——一个“仓库参数”弹窗直接列出选项tank-battle / 公开Recommended、tank-battle / 私有、tank-battle-game / 公开、Other。用户确认后它才动手。相比“先建了再说、发现可见性不对再修”事前确认参数显然是更文明的姿势。接下来一气呵成写一份完整的 README——特性总览、操作说明、4 种敌人图鉴与分值表、6 种道具效果表、技术架构图状态机/碰撞/绘制/AI/音效、三种运行方式直接打开/本地服务/公网部署、目录结构、扩展路线图写 .gitignore 排除 node_modules、.codeartsdoer/ 等工具目录git init 到 main 分支3 个文件tank_battle.html / README.md / .gitignore提交并推送服务端 Git Hooks 检查通过。有意思的是最后一步创建时仓库默认是私有private与弹窗里选择的公开不符。CodeArts 检查发现后没有含糊过去而是直接通过 API 把可见性修正为 public并在总结里如实注明“创建时仓库默认私有已通过 API 修正为公开与你选择一致。” 最终交付https://atomgit.com/guowei88/tank-battle本地 main 与 origin/main 完全一致。这一轮的收尾数据耗时 8 分 10 秒、缓存命中 100%、输入 121.2k tok、输出 3.9k tok。全链路流程图把整场会话压缩成一张 mermaid 流程图大致是这样的跳过 brainstorming无坦克模板No module named playwright默认private提示词: 帮我开发一个坦克大战, 纯HTML创造性工作检查既有技能匹配 game-maker 技能(游戏架构专家角色)状态机模板: IDLE→PLAYING→GAMEOVER主循环: 输入→更新→碰撞→渲染→反馈查脚本库/参考目录TODO 规划设计深潜: 13x13字符地图/碰撞/道具/关卡写入 tank_battle.htmltryMove滑墙/drawTank纯Canvaspython3 提取JS语法检查29855 chars OKPlaywright 可用?降级: puppeteer-core 系统 chromium浏览器实测三阶段截图favicon 404 修复30秒平衡验证HUD轮询, NO JS ERRORS13条逻辑路径全部通过用户确认交付52.1k tok / 1941 tok初始化AtomGit仓库指令ag auth status: 已认证 guowei88弹窗确认: 仓库名/可见性README .gitignoregit init main 分支 3 文件推送 tank-battle 仓库可见性与选择一致?API 修正为 public交付: atomgit.com/guowei88/tank-battle总结这次实践从头到尾一句话需求、一个技能、一次降级、一张清单、一个仓库。回顾整个过程它和“新手做个小游戏”最大的分野不在写代码的速度而在写代码之前和之后之前是把所有会返工的决定地图尺寸、碰撞采样、道具数值、关卡布局用字符画和常量表前置敲定之后是用四层验证把“能玩”从主观感觉变成可复核的事实。中间那段 playwright 缺失后的降级则是整场里我最想让大家记住的一幕——工具会缺席验证标准不能缺席。对想上手 AIGC 开发的新手我的建议还是那三条第一把范围收小先让 CodeArts 交出能运行的版本再拿具体画面去反馈本次“功能完成了吗”的确认就是标准的验收节奏第二盯着 CodeArts 的验证环节看它怎么查语法、怎么截图、怎么列逻辑路径比它写了什么代码更值得学第三交付物要有边界感——功能清单、文件位置、运行方式、已知问题比如那次如实注明的 private 修正一样都不能少。做到这三点AI 就是趁手的工程搭档做不到它只是个更快的打字员。坦克大战跑起来的那一刻红白机的音效从浏览器里传出来——这次是 CodeArts 替我们把童年搬进了现代浏览器还顺手教会了我们一整套把它发布出去的方法。