ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 vibe coding 13 天做出网页版怀旧挂机游戏:从需求到实现全复盘

用 vibe coding 13 天做出网页版怀旧挂机游戏:从需求到实现全复盘 很多人对 AI 写代码有一个误解觉得它只能做点小玩具真正像样的东西还是得靠人手敲。但这次我用 13 天完全以 vibe coding 的方式做了一个网页版的“QQ华夏挂机版”——有角色、有地图、有装备掉落、有离线收益还能存档读档。做完之后反而得出一个更强烈的判断vibe coding 真正改变的不是“不用写代码”而是“把想法变成可玩产品”的成本被压到了极低。18 年前那款端游是很多人第一款熬夜挂机的 MMORPG。怀念的不是游戏本身而是那个不用考虑工作 KPI、不用担心服务器账单、只需要关心一件装备掉没掉的年代。所以我就想能不能用现在的 AI 开发方式把当年最舒服的几个体验抽出来挂机打怪、装备随机掉落、角色成长、背包整理。这些玩法单看都不复杂但组合在一起反而是一个非常适合 vibe coding 的项目形态。这篇文章我会从几个角度展开为什么选挂机游戏作为 vibe coding 的载体vibe coding 的核心原理和工具链是什么这个项目的需求拆解与系统设计13 天开发工序的复盘核心系统的代码实现以及 AI 生成代码时最容易踩的坑和应对方式。如果你也想用 AI 快速做一个自己的小游戏、小工具或者单纯想搞清楚 vibe coding 到底适不适合你这篇文章应该能提供一个非常具体的参考。1. 为什么用 vibe coding 做一个怀旧挂机游戏先回答一个问题项目那么多为什么偏偏是挂机游戏原因是挂机游戏在结构上有一个天然优势它是数据驱动的。角色属性是一张状态表怪物掉落是一套随机规则战斗过程是一次次数值比较存档就是一个 JSON 对象。这类项目没有复杂的图形渲染、没有网络同步、没有高并发AI 生成代码时不容易出现“上下文爆炸”人也容易读懂每一步逻辑。而 vibe coding 的本质是让人用自然语言描述需求让 AI 完成大量编码再由人来验证结果。挂机游戏这种“系统多、反馈快、视觉结果明显”的项目几乎是为 vibe coding 量身定做的。做一个最小可玩版本只需要一个 HTML 文件加一个 JS 文件加一个装备系统本质上是加一张配置表和一个随机函数加一个地图切换也只是改几个按钮和数组。如果把目标换成“做一个完整的大型在线游戏”那我不建议任何人用 vibe coding 起步。复杂度会指数级上升AI 生成代码的幻觉也会变得难以追查。所以这里有一个很清晰的项目边界个人怀旧项目、原型验证、课程设计、内部工具适合 vibe coding生产级系统、强一致场景、涉及账务与权限的项目不适合。另一个选择这个项目的原因是情感驱动。写代码是一个高摩擦活动容易在一开始就陷入“这个类要怎么设计”“数据库表要不要建”这类细节里。但怀旧会让人跳过完美主义只想着“能跑起来就行”。这种心理状态和 vibe coding 的节奏非常匹配先跑通再打磨。2. vibe coding 是什么概念、原理与工具选型vibe coding 这个词最早由 Andrej Karpathy 在 2025 年提出。它描述的是一种新的开发方式由 AI 承担大部分编码任务人主要负责描述意图、检查输出、发现问题、再让 AI 修改。换句话说人的角色从“写代码的人”变成了“提需求的人和验收代码的人”。可以用一个对比表格来理解它和传统开发的区别开发方式代码由谁写代码由谁审人的核心工作传统开发人人写代码、单测、评审AI 辅助开发AI 为主人修改人 AI代码审查、重构、修 bug纯 vibe codingAI以 AI 自查为主人做结果验收描述需求、跑通验证、调方向需要强调的是vibe coding 不等于“什么都不懂也能开发”。人仍然需要理解系统边界、清楚自己要什么结果并且具备基本的排查能力。只不过这些能力的应用方式从“逐行写”变成了“逐模块验证”。工具链上vibe coding 的载体有好几类AI 编程助手在现有 IDE 里以插件形式存在适合在已有工程里做局部功能。AI 原生 IDE把对话、文件管理、终端整合在一起适合从零创建项目。在线 AI 应用平台比如 Vercel 这类 PaaS 平台也在尝试把 vibe coding 从本地推到云端AI 生成代码后直接连接数据库并完成部署。这类平台更适合“做完就能发布上线”的产品型项目。而这次做的怀旧挂机游戏我选择的是最朴素也最可控的方案纯前端单页应用 localStorage 存档。原因很简单这个项目不需要服务器不需要数据库也不需要联网登录。用原生 HTML、CSS、JavaScript 实现AI 生成代码时不需要猜测框架结构生成的代码是完整的、可读的也方便人逐行检查。技术栈越简单vibe coding 的成功率越高。这是整个项目里最重要的一条选型经验。3. 项目需求拆解与系统设计在开始让 AI 写代码之前我先做了需求拆解。注意这里拆的不是“游戏策划文档”而是“功能模块和数据结构”。我把整个项目拆成了七个核心系统系统核心数据交互方式角色系统等级、经验、HP、MP、攻击、防御角色面板展示战斗系统玩家属性、怪物属性、伤害公式每秒自动攻击地图系统地图 ID、怪物列表、等级范围地图切换按钮装备系统装备类型、品质、攻击/防御加成掉落拾取、穿戴背包系统物品列表、数量列表展示、丢弃商店系统商品表、价格购买按钮存档系统角色、背包、任务进度的 JSONlocalStorage 读写确定模块后我做了三个版本的规划M1 最小可玩版角色 怪物 自动战斗 经验升级。M2 系统扩展版装备掉落 背包穿戴 商店购买。M3 体验完整版多地图切换 任务系统 离线收益 存档读档。这个规划的用意是让 AI 每一步都只面对一个小目标。如果一开始就把七个系统一次性塞给 AI它生成的代码大概率会出现变量冲突、函数职责混乱、或者出现一个巨大无比且无法维护的 main.js。分段推进之后每一段代码都可以独立运行和验证。这里有一段我踩过的真实教训如果你让 AI 一次写完整全通版本它会默认你喜欢“完整”于是生成很多你还没想好的功能。比如我当时并没有规划宠物系统但 AI 在某个版本里主动加了一个宠物数组结果整个存档结构和装备穿戴逻辑都要跟着改。所以需求越原子化vibe coding 越好控制。4. 13 天开发工序复盘说是 13 天并不是 13 个整天。如果折算成有效时间大概也就是两三个完整工作日。这种“战线长、实际投入短”的状态恰好也是 vibe coding 的典型节奏每天抽一两个小时和 AI 对话、验证结果、调整方向然后关掉电脑去忙别的事。4.1 前 3 天先跑通最小可玩版本这 3 天只做一件事让角色站在地图上每秒钟打一只怪物怪物死了掉经验和金币经验够了升级升级后属性变强。AI 生成代码后我在浏览器里反复刷新确认数字在跳动、升级时比较顺畅。这一步是整个项目的定海神针。因为界面只有数字逻辑只有计算AI 生成出错也不难排查。一旦最小版本跑通后面所有系统都是在这个骨架上长出来的。4.2 中间 5 天逐个扩展子系统装备系统、背包、商店、地图切换这些都是在最小版本之后逐个加进去的。每加一个系统我只给 AI 一段简短的需求描述然后要求它复用之前的角色对象结构。期间最大的问题是 AI 偶尔会重新定义一个角色对象导致旧存档和新代码对不上。解决方法很朴素加存档版本号。这个阶段还锻炼了一个习惯每完成一个功能就手动刷新页面做一次回归确保之前的功能没有被新代码破坏。因为 vibe coding 的迭代速度太快旧功能被 AI 改坏是常态。4.3 最后 5 天打磨体验与数据平衡最后阶段打磨的是“手感”和“节奏”。比如怪物血量不能太厚否则挂机一小时只打一只怪装备词条不能太极端否则一件史诗装备就直接无敌。这些数值并不是我手工算出来的而是让 AI 生成一个参数表然后我根据实际跑出来的结果在对话里给它几轮修改指令。不得不说AI 调整数据平衡的能力比我预期的强。因为这类游戏本质上是一堆公式AI 很擅长从“现在升级太慢”这个模糊描述里推断出需要降低升级经验曲线。4.4 可以复用的方法论最后总结一下这个阶段最值得带走的经验一次只给 AI 一个小模块而不是一整份需求文档。每个模块完成后都手动验证确认没破坏旧功能。让 AI 在关键代码处加注释解释它的逻辑方便人审查。给存档加版本号避免迭代中读旧档崩溃。别急着让 AI 优化代码先把功能跑起来。优化是最后一步。5. 核心系统实现战斗、装备与存档这一章放几个核心代码示例。下面这些代码都是可以直接新建文件运行的版本为了展示完整流程我按模块拆分并标注了文件路径。5.1 角色属性与伤害计算文件路径js/character.jsfunction createCharacter(name) { return { name: name || 怀旧玩家, level: 1, exp: 0, hp: 100, maxHp: 100, mp: 50, maxMp: 50, attack: 12, defense: 5, gold: 0, mapId: qingyun, equipment: { weapon: null, armor: null, ring: null } }; } function getTotalAttack(character) { let base character.attack; const eq character.equipment; if (eq.weapon) { base eq.weapon.attack || 0; } if (eq.ring) { base eq.ring.attack || 0; } return base; } function getTotalDefense(character) { let base character.defense; const eq character.equipment; if (eq.armor) { base eq.armor.defense || 0; } if (eq.ring) { base eq.ring.defense || 0; } return base; } function computeDamage(attack, defense) { // 简单伤害公式攻击和防御都参与计算但至少保留 1 点伤害 return Math.max(1, Math.floor(attack * 0.6 - defense * 0.3)); }key point 是角色对象使用普通对象而不是 class。这样 AI 生成的代码不容易出现“this 指向混乱”的问题JSON 序列化存档时也更干净。很多 AI 默认会生成 ES6 class但在这种纯数据型项目里普通对象反而更稳。5.2 战斗循环与挂机收益文件路径js/fight.jslet fightTimer null; function startFight(character, monster, onUpdate) { stopFight(); fightTimer setInterval(() { // 玩家先手攻击怪物 const playerDamage computeDamage(getTotalAttack(character), monster.defense); monster.hp - playerDamage; if (monster.hp 0) { const reward onMonsterKilled(character, monster); onUpdate({ reward }); } else { // 怪物反击 const monsterDamage computeDamage(monster.attack, getTotalDefense(character)); character.hp - monsterDamage; if (character.hp 0) { stopFight(); onUpdate({ death: true }); } else { onUpdate({ playerDamage, monsterDamage }); } } }, 1000); // 每 1 秒攻击一次 } function stopFight() { if (fightTimer) { clearInterval(fightTimer); fightTimer null; } } function onMonsterKilled(character, monster) { const exp monster.exp || 10; const gold monster.gold || 5; character.exp exp; character.gold gold; let leveled false; while (character.exp getLevelUpExp(character.level)) { character.exp - getLevelUpExp(character.level); character.level 1; character.maxHp 20; character.maxMp 5; character.attack 3; character.defense 2; character.hp character.maxHp; character.mp character.maxMp; leveled true; } return { exp, gold, leveled }; } function getLevelUpExp(level) { return level * 50; }这段代码里最容易出问题的地方是setInterval。AI 生成的早期版本经常在 startFight 里没有先调用 stopFight导致用户切换地图后出现两个战斗循环同时跑伤害翻倍。所以这里有一个约定任何开启定时器的函数第一步永远是清理旧的定时器。5.3 装备随机生成与品质表文件路径js/equipment.jsconst EQUIP_TYPES { weapon: { name: 武器, attackRange: [5, 18], defenseRange: [0, 2] }, armor: { name: 护甲, attackRange: [0, 1], defenseRange: [4, 15] }, ring: { name: 戒指, attackRange: [2, 6], defenseRange: [1, 4] } }; function generateEquipment(monsterLevel) { const typeKeys Object.keys(EQUIP_TYPES); const type typeKeys[Math.floor(Math.random() * typeKeys.length)]; const cfg EQUIP_TYPES[type]; const attack randInt(cfg.attackRange[0], cfg.attackRange[1]) monsterLevel; const defense randInt(cfg.defenseRange[0], cfg.defenseRange[1]) monsterLevel; const quality getQuality(); const name ${quality}·${cfg.name}; return { id: eq_ Date.now() _ Math.floor(Math.random() * 9999), name, type, attack: Math.max(0, attack), defense: Math.max(0, defense), quality }; } function getQuality() { const roll Math.random(); if (roll 0.6) return 普通; if (roll 0.9) return 精良; if (roll 0.99) return 稀有; return 史诗; } function randInt(min, max) { return Math.floor(Math.random() * (max - min 1)) min; }装备系统的核心是“随机但有边界”。每个部位的攻防数值区间由attackRange和defenseRange控制再叠加怪物等级作为成长曲线。AI 生成这段逻辑时最容易出现的问题是随机数边界错误比如Math.random() * range没有1导致最高值永远取不到。所以在验证环节一定要反复测试掉落装备的上限值。5.4 localStorage 存档与读档文件路径js/save.jsconst SAVE_KEY qq_hx_afk_save_v1; function saveGame(character, bag, missions, timestamp) { const data { character, bag, missions, savedAt: timestamp || Date.now() }; // 先序列化再写入避免把 undefined 属性带进 localStorage const json JSON.stringify(data); localStorage.setItem(SAVE_KEY, json); } function loadGame() { const json localStorage.getItem(SAVE_KEY); if (!json) return null; try { return JSON.parse(json); } catch (e) { console.error(存档解析失败, e); return null; } } function clearSave() { localStorage.removeItem(SAVE_KEY); }存档版本号v1是必须的。因为后续每加一个系统存档结构就变一次。没有版本号的存档在代码迭代后很容易出现读旧档崩溃的问题。loadGame 里加try/catch也是为了防止用户手工改坏 localStorage 后导致整个页面白屏。最后需要一个 HTML 文件把这些 JS 串起来。这里只展示引入顺序完整的按钮和界面可以交给 AI 根据你的需求生成。!-- index.html 部分片段 -- script srcjs/character.js/script script srcjs/equipment.js/script script srcjs/fight.js/script script srcjs/save.js/script script srcjs/main.js/script注意 JS 文件的引入顺序不能乱。因为 character.js 提供了基础对象构造函数fight.js 依赖它save.js 又被 main.js 调用。这个顺序是 AI 容易忽略的地方如果引入顺序错了控制台会直接报“xxx is not defined”。6. 运行验证与效果检查这个项目是纯前端项目运行方式有两种。方式一直接双击打开 index.html。适合快速看效果但如果用到了浏览器的某些本地文件限制可能会有跨域报错。方式二本地起一个静态服务更接近真实页面环境。cd qq-hx-afk python3 -m http.server 8080然后在浏览器打开http://localhost:8080。第一轮运行后建议按照下面的清单做验收验证项预期结果失败时的排查方向角色正常创建显示默认属性无控制台报错查看 JS 文件引入顺序战斗自动开始HP/怪物血量每秒变化检查 fightTimer 是否被清理怪物死亡掉落金币、经验增加可能掉落装备检查 onMonsterKilled 返回逻辑升级触发等级增加属性提升查看升级循环是否死循环装备穿戴总攻击/防御变化检查 getTotalAttack 计算逻辑刷新页面角色状态保持确认 localStorage 有写入点击新地图怪物列表切换检查地图数组配置如果第一轮验证失败先不要急着让 AI 改代码。打开浏览器控制台看报错信息把报错原样复制给 AI它通常能很快定位问题。vibe coding 的核心习惯之一就是把错误信息当对话素材而不是自己埋头查。7. AI 生成代码的常见问题与排查方法这一章是整套流程里最值得记录的部分。vibe coding 体验很爽但 AI 生成的代码并不是无懈可击的。下面是我在这个项目里遇到过的典型问题整理成一张排查表问题现象可能原因排查方式解决方案刷新页面后存档丢失localStorage 存储失败检查浏览器隐私模式或控制台报错明确使用 localStorage并给 key 加版本号战斗速度越来越快setInterval 存在多个实例查看 F12 Performance 或日志中 timer 数量startFight 开始前先 stopFight数值溢出装备攻击为负数随机数上下界写反了打印掉落装备的原始值在 randInt 函数里手动测试边界AI 使用了不存在的浏览器 API上下文窗口不够混淆了 API查看控制台具体报错在需求里强制限制“只用浏览器原生 API”修改装备系统后旧存档崩溃存档结构变化缺少兼容逻辑检查 JSON.parse 后字段是否存在给存档加版本号并写字段默认值某个按钮点击无效事件绑定没有执行在函数开头加 console.log 验证让 AI 修复事件绑定逻辑CSS 布局全乱AI 混用了多个布局方案检查元素计算样式重置为 flex 纵向布局再逐层调整角色升级后 HP 不刷新升级逻辑和 UI 更新分离查看 onUpdate 回调是否传了 character让升级逻辑返回完整角色对象如果出现多个问题同时发生按这个顺序排查控制台报错 → 引入顺序 → 本地存储 → 定时器冲突 → 数据边界。绝大多数问题都集中在这五类里。8. vibe coding 的实践边界与工程建议写了这么多最后还是要回到一个清醒的判断vibe coding 适合什么不适合什么。从这次项目看它非常适合以下场景个人项目游戏、工具脚本、博客系统、网页小应用。原型验证先跑通一个粗糙版本验证产品想法是否可行。课程设计用最短时间完成可演示的项目。内部效率工具一次性脚本、数据清洗、报表生成。但它不适合以下场景生产级高并发系统AI 对性能瓶颈和数据一致性的理解有限。涉及支付、账务、权限的系统错误代价太高人必须逐行审计。需要长期维护的大型工程AI 生成代码的风格可能前后不一会导致后续维护成本上升。对数据正确性有严格要求的场景比如医疗、金融、自动化控制。工程建议上有几条是反复验证过的第一最小可运行版本永远最先做。别让 AI 先写配置文件、单元测试、项目文档。先跑通一个最小闭环后面再补。第二需求描述要精确到“输入、处理、输出”。不要只说“加一个背包系统”要说“背包是一个数组存放装备对象点击装备可以穿上再点可以脱下”。这样 AI 生成的代码更可控。第三要求 AI 写注释和解释。让 AI 在关键函数前加注释说明它这么写的理由。这不仅是代码规范也是人审查代码时最重要的依据。第四用版本管理工具保留每一步状态。哪怕是个人项目也建议用 Git。vibe coding 迭代速度太快AI 可能改出一个更差的版本回滚是常态。第五定期把整个代码文件扔回给 AI 做一次自查。比如“请检查 character.js 有没有潜在 bug以及存档兼容性”。AI 换个上下文重新看自己的代码经常能发现隐藏问题。第六安全边界要提前说清楚。这个项目只用了 localStorage没有网络请求也没有处理任何敏感信息。如果项目涉及用户输入和账号体系一定不要在 vibe coding 流程里跳过安全审查。9. 总结与后续学习方向这篇文章写到现在最想传递的判断是vibe coding 不会取代程序员但它真的改变了“一个人能做多少东西”的边界。13 天做一个能玩的怀旧挂机游戏在传统模式下至少要几周还得会 CSS、JavaScript、游戏循环、存档设计。而在 vibe coding 的流程里我更多的时间花在“描述需求、验证结果、调整数据”上。如果你也想尝试建议不要从巨复杂的项目开始更不要一上来就规划一个联网大型系统。找一个你一直想实现的、边界清晰的小东西一个游戏、一个工具页面、一个自动化脚本。用 10 分钟把需求说清楚用一下午让 AI 把第一版跑起来。那个“真的能用了”的瞬间你会更直观地理解开发工具进化到了什么阶段。这个项目的后续方向也有不少可以深挖的地方把数据量提升一档学习 React 或 Vue 组织界面把存档迁移到云端体验一下数据库和接口的设计甚至可以把整个项目交给 Vercel 这类平台一键部署做成一个随时能在手机上打开的小网站。每一层深入都会接触到比 vibe coding 本身更扎实的工程能力。这篇文章不是让你放弃学习基础而是提供一个非常具体的起点让 AI 帮你快速完成第一版然后用真实的运行效果驱动你继续往下学。18 年前的网游时光已经回不去了但“做游戏”的快乐在现代开发工具的加持下反而变得比以前更容易触达。
返回列表