ARTICLE DETAIL

资讯详情

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

AI辅助编程实战:13天构建复古MMORPG挂机游戏全复盘

AI辅助编程实战:13天构建复古MMORPG挂机游戏全复盘 14年前的一个深夜我在网吧的角落里盯着一只“幻蛛”刷新。旁边的大哥在带人刷“北郡”的副本耳机里传来《诛仙》的BGM。那时候没有“挂机”这个词至少对大部分玩家来说挂机还是一种会被踢出队伍的行为。18年后我已经是一个写了十几年代码的老程序员。工作台前不再是熙熙攘攘的网吧而是显示器、机械键盘和一杯冷掉的咖啡。过去那些MMORPG大多已经关服或者变成空壳想再登录看一眼当年创建的“刺客”角色都找不到入口。这个夏天我用13天在浏览器里重新做了一个“QQ华夏挂机版”。它不是当年的那个游戏甚至不能算精神续作。它只是我用AI辅助编程的方式把那段记忆里的核心玩法抽象出来刷怪、升级、掉装备、洗属性、看排行榜。没有美术原画没有复杂特效地图是一块粗糙的Canvas画布怪物是几个圆形的色块。但当我第一次看到角色自动击杀怪物、经验条缓慢上涨、掉落一地的装备时那种感觉像极了当年第一次在华夏城门口打死一只小怪。这篇文章不是游戏评测也不是商业分析而是我作为开发者从0到1用vibe coding方式构建这个挂机游戏全过程的复盘。我会讲清楚架构设计、核心代码实现、AI协作模式以及在这个过程中踩过的坑。如果你也想用AI辅助方式做一个自己的复古项目这篇文章应该能让你少走很多弯路。1. 这篇文章真正要解决的问题先说清楚这篇文章的边界它不是一个完整的游戏开发指南而是围绕“AI辅助编程vibe coding 复古MMORPG挂机玩法”的一套实操方法论。这几年AI辅助编程已经从“自动补全代码”进化到了“跟着你一起设计系统”的层面。所谓vibe coding简单说就是你用自然语言描述需求AI生成代码你再基于运行结果调整需求如此循环往复。它降低的不是“写代码”的门槛而是“从想法到可运行原型”的门槛。但这也带来了一个新的问题AI生成的代码能不能撑起一个有完整系统的项目挂机游戏恰好是一个非常好的实验场。它不需要复杂的物理引擎不需要设计精妙的关卡但它需要一个完整的游戏循环角色成长、怪物刷新、战斗计算、物品掉落、背包管理、装备穿戴、任务系统、排行榜。这些系统每一个都不难但连在一起对代码质量和架构能力是有要求的。我的目标是验证一个判断在AI辅助下一个非游戏行业出身的后端程序员能否在两周内构建一个架构相对清晰、可运行、可扩展的复古老网游挂机版。答案是肯定的但前提是你要理解AI生成的代码规律并且自己掌握架构设计和系统分解的能力。AI不是替你写游戏而是替你写那些你已经想清楚逻辑的代码。它帮你省掉的是打字时间、查API时间、写模板代码的时间但省不掉设计、调试和验证的时间。2. 为什么是“挂机版”而不是“完整版”当年玩QQ华夏时最让人上头的不是手动操作的爽快感而是那种“角色在世界里自动成长”的陪伴感。放学回家打开电脑登录游戏角色在城外自己打怪偶尔弹出“你获得了一件XX装备”的提示。那是一种介于游戏与虚拟花园之间的体验。所以当我决定复刻这个记忆时第一选择就是做“挂机版”。什么叫挂机版核心特征有三个角色自动寻怪、自动攻击、自动释放技能。战斗结果基于数值计算而不是操作技巧。核心乐趣在于“积累与随机”——经验条漫漫上涨、装备随机掉落、属性随机生成。这意味着我几乎可以忽略掉所有与客户端表现相关的复杂技术把精力集中在游戏逻辑与数据系统上。挂机版的关键技术点是“战斗模拟”而不是“战斗表现”。从工程角度看挂机版天然适合Web技术实现。它不需要60帧的连续渲染不需要帧同步甚至不需要WebSocket做频繁的实时通信。大部分逻辑可以在服务端以固定时间片为单位进行模拟然后通过API把战斗结果推给前端展示。这也是很多AI辅助编程初学者最好上手的游戏类型系统边界清晰数据可以结构化AI生成的代码容易验证。3. 项目架构设计与技术选型这个项目的技术选型我尽量保持了克制。没有用重型框架也没有引入复杂的中间件核心目标是在最短时间内跑通完整游戏循环。3.1 整体架构浏览器前端HTML Canvas JavaScript ↓ HTTP / WebSocket 后端服务Node.js Express WebSocket ↓ 读写 数据存储SQLite JSON 文件你可能会问为什么不用Python因为挂机游戏本质上是高频率的数据状态变更Node.js的事件循环模型天然适合这种场景。而且前后端同用一种语言AI生成代码时跨语言转换的bug少很多。3.2 核心数据模型游戏中最核心的数据模型有五个玩家角色、怪物、装备、背包、战斗日志。玩家角色的核心字段{ playerId: player_001, name: 怀念华夏, level: 1, exp: 0, expNext: 100, hp: 100, maxHp: 100, mp: 50, maxMp: 50, attack: 15, defense: 5, critRate: 0.1, gold: 0 }装备的核心字段{ itemId: item_10001, name: 青铜剑, type: weapon, level: 1, attackBonus: 10, defenseBonus: 0, hpBonus: 0, critBonus: 0.02 }3.3 为什么选SQLite挂机游戏有一个特点逻辑跟存储是高度分离的。玩家离线时不需要实时计算只需要在下次登录时根据离线时长结算收益。所以数据库不需要很高的并发但需要快速启动、零配置、文件存储方便迁移。SQLite是最合适的选择。它不需要单独部署数据库服务所有数据在单一文件里备份和迁移都很简单。AI写SQLite的代码时出错率也低。3.4 前端渲染策略前端我不打算做成一个复杂的客户端。Canvas上绘制地图、角色、怪物用简单的几何图形表示。UI层用普通HTMLCSS操作也是按钮点击。关键点是前端不做游戏逻辑只做展示与指令。所有战斗计算、掉落判定都放在服务端前端每隔1秒请求一次状态接口渲染最新的画面。这种设计的好处是你不用担心玩家作弊修改数值也简化了后端逻辑的验证。挂机游戏本身对实时性要求不高1秒的轮询已经足够流畅。4. 开发流程从一句话需求到完整系统vibe coding的工作方式不是“让AI一口气写完整个游戏”而是“喂给它一个清晰的任务切片”。我的开发流程分成了七天第一天定义系统边界我做的第一件事不是写代码而是把所有功能列成一张表角色系统创建角色、显示属性、升级。战斗系统自动搜索怪物、攻击、受击、死亡、经验与金币结算。掉落系统击杀怪物后根据掉落表生成装备。背包系统拾取、查看、丢弃、穿戴装备。装备系统穿脱装备、属性计算。任务系统简单的主线任务按等级解锁。排行榜统计全服玩家的等级、战力。然后将这个功能表作为需求的“总纲”提交给AI。接下来每一天只让AI做一个或两个系统。第二天搭建项目骨架用AI生成项目基础结构入口文件、配置文件、数据库初始化、路由框架。npm init -y npm install express better-sqlite3 cors wsAI生成的核心入口文件// 文件路径server/index.js const express require(express); const http require(http); const { WebSocketServer } require(ws); const cors require(cors); const gameLoop require(./core/gameLoop); const routes require(./routes); const app express(); app.use(cors()); app.use(express.json()); const server http.createServer(app); const wss new WebSocketServer({ server }); app.use(/api, routes); gameLoop.start(); const PORT process.env.PORT || 3000; server.listen(PORT, () { console.log(游戏服务器启动端口 ${PORT}); });这里要强调一点AI生成的代码你需要花时间理解每一行在干什么因为它会默认你用的是特定版本的模块和API。如果依赖版本变化AI生成的代码可能会直接跑不起来。第三天角色系统与战斗系统角色系统是比较基础的CRUDAI很轻松就能完成。战斗系统是核心难点需要你手动设计战斗公式然后让AI实现。战斗公式我用了很经典的设计实际伤害 攻击力 * (1 - 防御力 / (防御力 100)) * 随机浮动(0.9 ~ 1.1)防御力减伤公式来自很多老MMORPG的经典设计它避免了“防御力直接抵消伤害”带来的零伤害问题同时保证了数值成长仍然有正反馈。AI生成的战斗核心代码// 文件路径server/core/combat.js function calculateDamage(attacker, defender) { const baseDamage attacker.attack; const defenseFactor defender.defense / (defender.defense 100); const reducedDamage baseDamage * (1 - defenseFactor); const critMultiplier Math.random() attacker.critRate ? 2.0 : 1.0; const randomFactor 0.9 Math.random() * 0.2; return Math.max(1, Math.floor(reducedDamage * critMultiplier * randomFactor)); } function battleRound(player, monster) { const playerDamage calculateDamage(player, monster); monster.hp - playerDamage; if (monster.hp 0) { return { result: victory, monsterHp: 0, playerDamage }; } const monsterDamage calculateDamage(monster, player); player.hp - monsterDamage; if (player.hp 0) { return { result: defeat, playerHp: 0, monsterDamage }; } return { result: continue, playerHp: player.hp, monsterHp: monster.hp, playerDamage, monsterDamage }; } module.exports { calculateDamage, battleRound };这里的逻辑很简单但要注意一个细节随机函数的使用。AI在生成战斗代码时容易把Math.random()的调用位置和次数搞混从而影响掉宝随机数的“公平性”。我建议所有随机判定都统一封装到一个函数里避免AI生成代码时引入偏差。第四天怪物系统与掉落系统怪物系统是挂机游戏的核心引擎。挂机循环的本质是角色每隔一段时间攻击一只怪物怪物死亡后计算掉落然后刷新下一只怪物。这里有一个重要的设计决定怪物刷新的模式。我选择了“每只怪物死亡后根据地图配置的刷新时间生成下一只”而不是常见的“定时批量刷新”。原因很简单挂机场景通常只有单个玩家在刷逐个刷新更容易控制和验证。掉落系统的核心是掉落表{ monsterId: monster_101, monsterName: 灰狼, level: 3, maxHp: 80, attack: 12, defense: 3, expReward: 25, goldReward: 10, dropTable: [ { itemId: item_10001, name: 青铜剑, dropRate: 0.05 }, { itemId: item_10002, name: 布甲, dropRate: 0.08 }, { itemId: item_20001, name: 生命药水, dropRate: 0.2 } ] }AI生成掉落判定代码时我特别加了注释让它不要用“多次随机”方式来简化为“概率叠加”而是用Math.random()与dropRate直接比较。// 文件路径server/core/drop.js function rollDrop(monsterConfig) { const drops []; for (const item of monsterConfig.dropTable) { if (Math.random() item.dropRate) { drops.push({ ...item }); } } return drops; }这里有个容易踩的坑掉落表的概率是独立判定不是“要么掉一个要么不掉”。如果你想让同一只怪物最多掉一件装备就需要额外的逻辑控制。这个需求要在需求描述里直接告诉AI否则AI会傻乎乎地把所有掉落算在一起导致怪物一次掉5件装备。第五天背包与装备穿戴背包和装备穿戴是典型的“状态变更”系统。玩家拾取物品后物品进入背包穿戴装备后装备属性被叠加到角色属性上。这部分的重点不是AI能不能生成代码而是物品的实例化与配置分离。物品配置item config是静态的、共享的而背包里的每一件物品都应该有唯一的instanceId这样才能描述“两把一模一样的青铜剑都占背包空间”的情况。AI在这个阶段容易犯的错是把物品配置当实例直接修改配置的属性。如果AI把装备穿戴写成修改配置对象那么所有同类型装备都会被改变。这个问题发生过一次当时给我的“青铜剑”攻击力从10变成了100然后所有玩家都拥有了100攻的青铜剑。解决方案是明确的所有装备实例在进入背包时必须深拷贝配置数据生成独立的实例对象。// 文件路径server/core/inventory.js function createItemInstance(itemConfig) { return { instanceId: generateId(), itemId: itemConfig.itemId, name: itemConfig.name, type: itemConfig.type, attackBonus: itemConfig.attackBonus, defenseBonus: itemConfig.defenseBonus, hpBonus: itemConfig.hpBonus, critBonus: itemConfig.critBonus }; }第六天任务系统与排行榜任务系统是挂机游戏有没有“目标感”的关键。我设计了最简单的两个任务类型击杀指定怪物N只、达到指定等级。任务进度在服务端维护玩家每次击杀怪物后后端判断是否满足任务条件满足则更新进度。任务完成后玩家可以在任务面板手动领取奖励。排行榜用SQL查询实现按等级、战力排序取前50名。不需要缓存因为单服在线人数不会很多直接查库也没问题。第七天前端界面与体验打磨前端是一个单页HTML文件包含角色面板等级、经验、属性、装备。战斗区域Canvas绘制背景、怪物、伤害数字。背包面板物品列表、装备穿戴按钮。任务面板任务进度、领奖按钮。排行榜Top50玩家。这一块用AI生成很高效但注意AI生成的UI代码容易“看起来还行但逻辑一团糟”。事件的绑定、数据的刷新、加载状态的展示这些细节需要你逐行检查。最终的打磨花了两天比写后端还久。5. 完整示例与代码实现现在进入核心部分。我会把几个最关键的实现贴出来包括挂机循环、战斗计算、掉落、背包操作、数据存储。5.1 挂机循环挂机循环是整个游戏的心脏。它每隔一个时间片这里设置为1秒执行一次检查玩家是否在战斗、是否存活、是否有怪物可打。// 文件路径server/core/gameLoop.js const { getPlayer, updatePlayer } require(../db/player); const { getMonster, updateMonster } require(../db/monster); const { battleRound } require(./combat); const { rollDrop } require(./drop); const { addItemToInventory, getInventory } require(./inventory); const { getMonsterConfig } require(../config/monsters); const { updateTaskProgress } require(./task); const battleState new Map(); function startGameLoop() { setInterval(async () { const players await getAllActivePlayers(); for (const player of players) { await processPlayerTick(player); } }, 1000); } async function processPlayerTick(player) { let state battleState.get(player.id); if (!state || state.monsterHp 0) { // 获取当前地图的怪物配置生成一只新怪物 const monsterConfig getMonsterConfigByLevel(player.level); state { monsterId: monsterConfig.monsterId, monsterHp: monsterConfig.maxHp, monsterConfig }; battleState.set(player.id, state); } // 玩家和怪物各攻击一次完成一个回合 const monsterObj { attack: state.monsterConfig.attack, defense: state.monsterConfig.defense, hp: state.monsterHp }; const result battleRound(player, monsterObj); if (result.result victory) { // 怪物死亡结算经验和掉落 const expGain state.monsterConfig.expReward; const goldGain state.monsterConfig.goldReward; player.exp expGain; player.gold goldGain; updateTaskProgress(player.id, kill, state.monsterConfig.monsterId, 1); const drops rollDrop(state.monsterConfig); for (const drop of drops) { await addItemToInventory(player.id, drop); } // 检查升级 checkLevelUp(player); await updatePlayer(player); // 清空状态下一帧刷新怪物 state.monsterHp 0; } else if (result.result defeat) { // 玩家死亡扣少量金币作为惩罚然后重置在安全区域 player.gold Math.max(0, player.gold - 5); player.hp player.maxHp; await updatePlayer(player); } else { // 继续战斗保存中间状态 state.monsterHp result.monsterHp; player.hp result.playerHp; await updatePlayer(player); } }这个循环里有几个关键点用Map保存每个玩家的实时战斗状态避免频繁读数据库。挂机游戏状态下玩家的战斗数据是高频变化的不适合每次都写入数据库。胜利后清空怪物的HP下一tick才会生成新怪物这是“死一只刷一只”的实现。玩家死亡处理比较简单扣少量金币满血复活。没有做死亡冷却因为挂机游戏最忌讳打断挂机节奏。5.2 经验与升级公式经验公式决定了游戏节奏。我用了经典的三次方曲线增长率// 文件路径server/core/levelFormula.js function expRequiredForLevel(level) { return Math.floor(50 * Math.pow(level, 1.8)); } function checkLevelUp(player) { while (player.exp expRequiredForLevel(player.level)) { player.exp - expRequiredForLevel(player.level); player.level 1; // 升级属性成长 player.maxHp 15; player.hp player.maxHp; player.maxMp 5; player.mp player.maxMp; player.attack 3; player.defense 2; } }这个公式的寓意是前期升级很快给玩家正反馈。到了20级以后升级速度肉眼可见地变慢拉起长线目标。5.3 背包操作与装备穿戴背包系统的关键逻辑// 文件路径server/db/inventory.js const Database require(better-sqlite3); const db new Database(./game.db); function getInventory(playerId) { return db.prepare(SELECT * FROM inventory WHERE player_id ?).all(playerId); } function addItemToInventory(playerId, item) { const existingItem db.prepare( SELECT * FROM inventory WHERE player_id ? AND item_id ? ).get(playerId, item.itemId); if (existingItem) { db.prepare( UPDATE inventory SET quantity quantity 1 WHERE id ? ).run(existingItem.id); } else { const result db.prepare( INSERT INTO inventory (player_id, item_id, name, type, attack_bonus, defense_bonus, hp_bonus, crit_bonus, quantity) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1) ).run(playerId, item.itemId, item.name, item.type, item.attackBonus, item.defenseBonus, item.hpBonus, item.critBonus); return result.lastInsertRowid; } } function equipItem(playerId, inventoryId) { const item db.prepare( SELECT * FROM inventory WHERE id ? AND player_id ? ).get(inventoryId, playerId); if (!item) { throw new Error(物品不存在); } const player db.prepare(SELECT * FROM players WHERE id ?).get(playerId); // 穿戴装备将装备加成加到玩家属性上 db.prepare( UPDATE players SET attack attack ?, defense defense ?, maxHp maxHp ?, hp hp ?, critRate critRate ? WHERE id ? ).run( item.attack_bonus, item.defense_bonus, item.hp_bonus, item.hp_bonus, item.crit_bonus, playerId ); db.prepare(UPDATE inventory SET equipped 1 WHERE id ?).run(inventoryId); }这里要注意装备穿戴后是把属性加成加到玩家身上。如果脱下装备需要把加成减掉。这个“加/减”的方案容易在实现时出错AI容易搞混哪个字段加、哪个字段减。最好在写需求时明确告诉AI“穿戴是加法脱下是减法属性来源全部记录在背包中通过equipped字段标识”。5.4 前端渲染代码前端用Canvas绘制战斗场景。代码主要是接收后端接口的数据更新画面。// 文件路径client/index.js const canvas document.getElementById(gameCanvas); const ctx canvas.getContext(2d); function drawGame(state) { // 清空画布 ctx.clearRect(0, 0, 800, 450); // 绘制地面简单网格 drawGrid(); // 绘制怪物 if (state.monster) { const mx 400; const my 250; ctx.fillStyle state.monster.defeated ? #999999 : #cc3333; ctx.beginPath(); ctx.arc(mx, my, 25, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle #ffffff; ctx.font 14px Arial; ctx.textAlign center; ctx.fillText(state.monster.name, mx, my - 30); // 绘制血量条 ctx.fillStyle #333333; ctx.fillRect(mx - 30, my 30, 60, 6); ctx.fillStyle #44ff44; ctx.fillRect(mx - 30, my 30, 60 * (state.monster.hp / state.monster.maxHp), 6); } // 绘制玩家 const px 350; const py 250; ctx.fillStyle #3399ff; ctx.beginPath(); ctx.arc(px, py, 20, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle #ffffff; ctx.font 12px Arial; ctx.textAlign center; ctx.fillText(state.player.name, px, py - 25); // 绘制伤害数字 state.damageNumbers?.forEach((num, index) { ctx.fillStyle num.crit ? #ff9900 : #ffffff; ctx.font num.crit ? 18px Arial : 14px Arial; ctx.fillText(num.value, px 40, py - 20 - index * 20); }); // 绘制经验条 const expBarWidth 200; ctx.fillStyle #000000; ctx.fillRect(300, 430, expBarWidth, 10); ctx.fillStyle #ffcc00; ctx.fillRect(300, 430, expBarWidth * (state.player.exp / state.player.expNext), 10); }挂机游戏的画面本身不需要复杂角色、怪物、血条、经验条、伤害数字。当你看到自己叠出来的数字不断在屏幕上跳动时那种“挂机”的感觉就出来了。6. 运行结果与效果验证所有代码写完在本地运行node server/index.js启动后打开浏览器访问http://localhost:3000。预期效果页面加载后创建一个角色。角色自动开始寻找怪物并战斗。每隔一段时间怪物死亡经验条上涨金币增加。15%左右的概率掉落装备。达到升级经验时角色升级属性提升。我在测试时使用了简单的自动化脚本模拟挂机500秒验证几个关键指标角色等级从1级升到5级左右。金币增长正常没有出现负数。背包中随机出现装备没有出现重复实例覆盖问题。排行榜正常更新。如果运行失败第一步检查的是node -v确认Node.js版本满足要求。然后查看服务端终端输出是否有数据库初始化失败、端口占用、模块依赖缺失等问题。用浏览器开发者工具F12查看网络请求确认API返回状态码不是5xx。7. 常见问题与排查思路这个项目在开发过程中的高频问题如下问题现象可能原因排查方式解决方案启动报module not found依赖没有安装查看node_modules目录执行npm install端口被占用上次进程没有退出查看3000端口占用lsof -i :3000然后 kill 进程角色攻击怪物后怪物血量不变战斗状态存到了服务端内存但前端每1秒请求的是旧缓存检查后端是否更新了战斗状态修改gameLoop中的battleState更新逻辑掉落物没有进入背包背包表结构不正确或事务没有提交查看数据库中的inventory表检查addItemToInventory的数据库操作是否返回ID穿戴装备后攻击力没变装备穿戴逻辑没有更新玩家属性查看玩家属性字段检查equipItem中属性加成的SQL语句掉落概率感觉偏高随机数生成与掉落判定耦合在一起打印多组随机数单独封装随机函数统一管理升级后血量和攻击不变没有触发checkLevelUp检查升级逻辑是否在战斗结束后调用在胜利结算后调用升级函数这里特别要说一下第一个问题module not found在AI辅助开发中出现频率很高。原因是AI默认你安装了某些依赖但你的package.json里没有。简单的排查方式是每次AI生成新代码后检查代码中所有require的模块对照package.json的依赖列表有缺的直接补装。8. 最佳实践与工程建议8.1 AI辅助开发的“需求切片”原则不要对AI说“帮我做一个完整游戏”而应该拆成十几个小任务每个任务包含清晰的输入、输出、约束条件。好的需求切片应包含背景这个模块在整个系统中的位置。输入给定的数据格式和来源。处理核心逻辑步骤。输出期望的数据格式。约束如“不要修改其他模块”“数据库操作必须用事务”“返回错误码时统一格式”。8.2 数值配置与代码分离游戏数值怪物属性、掉落表、装备属性、经验公式应该放在独立的JSON配置文件中而不是硬编码在代码里。好处是你可以随时调数值而不需要改代码、重新部署。我自己在开发初期就是把怪物属性写在代码里结果每次调试都要重启服务器。后来把配置抽出来体验好很多。// 文件路径config/monsters.json { monsters: [ { monsterId: monster_101, name: 灰狼, level: 3, maxHp: 80, attack: 12, defense: 3, expReward: 25, goldReward: 10, respawnTime: 1, dropTable: [ { itemId: item_10001, name: 青铜剑, type: weapon, attackBonus: 10, defenseBonus: 0, hpBonus: 0, critBonus: 0.02, dropRate: 0.05 }, { itemId: item_10002, name: 布甲, type: armor, attackBonus: 0, defenseBonus: 5, hpBonus: 10, critBonus: 0, dropRate: 0.08 }, { itemId: item_20001, name: 生命药水, type: consumable, hpRestore: 50, dropRate: 0.2 } ] } ] }8.3 状态持久化策略挂机游戏有一个问题玩家可能连续在线几小时状态量很大。如果每一秒都写数据库会导致磁盘IO过高。我的策略是战斗实时状态保存在内存battleStateMap。每隔10秒批量写入一次玩家经验、金币、等级。背包和装备变更时立即写入数据库因为掉落频率不高。玩家心跳检测超过60秒无心跳则判定离线结算离线收益。这套策略在单服几百人的规模下完全够用。8.4 如何避免AI生成的“逻辑黑箱”AI生成代码最大的问题不是有bug而是你很难判断它为什么这么写。尤其是当你让AI优化一段代码时它可能会重构成一个你完全看不懂的实现看起来更简洁但行为发生了变化。我的建议是让AI写代码时同时要求它给出解释。在需求描述末尾加上一句“请在代码关键位置用中文注释解释设计意图”。这样即使代码逻辑有问题你也能读懂它的思路快速定位bug。8.5 安全边界挂机游戏虽然内部使用但暴露在公网部署时仍需注意API接口需要简单的token鉴权防止随意调用。前端与服务端的交互数据需要做基础校验防止通过API直接修改玩家属性。定期备份SQLite数据库文件。生产环境建议使用进程守护工具比如pm2避免进程意外退出。pm2 start server/index.js --name qq-huaxia-idle pm2 save pm2 logs9. 从vibe coding到真正的游戏开发13天做完这个“QQ华夏挂机版”我的收获不只是代码而是对AI辅助编程边界的一次验证。AI真正擅长的是生成模板代码、实现明确算法、批量生成配置、重构重复代码。它在“用键盘打字”这个层面效率是人类程序员的几倍甚至十倍。但AI不擅长的是理解你的产品意图、平衡游戏数值、确认系统边界。这些仍然需要人的判断。vibe coding的核心能力其实不是“会问AI问题”而是“会拆解系统”。你能把复杂系统拆成一个个最小可验证的模块AI才能一砖一瓦地帮你把房子建起来。如果没有这个能力AI生成代码的成本最终会变成你排错和重构的时间成本甚至比你自己写代码更慢。这款挂机游戏最终跑了三天三夜角色从1级升到了47级背包里攒了一堆属性各异的装备排行榜上有一个从没掉过线的角色遥遥领先。我关掉服务器把数据库备份保存好。那感觉就像当年把 QQ华夏的角色停在了安全区你知道它不会再更新了但它曾经陪过你一段时间。如果你想复刻这个项目我建议你从一个更小的范围开始只有一只能被击杀的怪物一个角色一本能加属性的日志。跑通循环再把系统一个个加进去。AI能帮你加速但只有你能决定它走向哪里。如果你卡在哪一步欢迎在评论区留下你的问题。收藏这篇文章下次写你的复古游戏时回来翻翻配置文件和战斗公式会省很多时间。
返回列表