如何用游戏化设计让 AI 编程变得更好玩
其实传统的 AI 编程工具功能挺强大的,就是少了点温度。我们在做 HagiCode 的时候就想,既然都要写代码,为什么不把它变成一场游戏呢?
背景
用过 AI 编程助手的朋友应该都有这种体验:刚开始觉得挺新鲜,用着用着就感觉少了点什么。工具本身功能很强大,代码生成、自动补全、Bug 修复样样都能做,只是……没什么温度,用久了会觉得有些单调乏味。
这也罢了,毕竟谁愿意每天对着冷冰冰的工具呢。
这就好比打游戏,如果只是单纯地完成任务列表,没有角色成长、没有成就感解锁、没有团队配合,那很快就会觉得没意思。美的事物或人,不一定要占有,只是她还是美的,自己好好看着她的美就好了。可编程工具连这种美都没有,难免让人心灰意冷。
我们在开发 HagiCode 的过程中就遇到了这个问题。HagiCode 作为一个多 AI 助手协作平台,需要让用户长期保持使用热情。但现实是,再好的工具,如果缺乏情感连接,用户也很难坚持下去。
为了解决这个痛点,我们做了一个大胆的决定:把编程变成一场游戏。不是那种简单的积分排行榜,而是真正的角色扮演式的游戏化体验。这个决定带来的变化,可能比你想象的还要大。
毕竟,人嘛,总是需要点仪式感的。
关于 HagiCode
本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个多 AI 助手协作平台,支持 Claude Code、Codex、Copilot、OpenCode 等多种 AI 助手协同工作。如果你对多 AI 协作、游戏化编程感兴趣,可以访问 github.com/HagiCode-org/site 了解更多。
其实也没什么特别的,只是我们把编程变成了一场冒险而已。
为什么选择游戏化
游戏化的本质不是"加个积分榜",而是建立一套完整的激励体系,让用户在做任务的过程中体验到成长感、成就感和社交认同。
HagiCode 的游戏化设计围绕一个核心概念展开:每个 AI 助手都是一名"英雄",用户就是这支英雄团队的队长。你带领这些英雄去征服各种"地牢"(编程任务),在这个过程中,英雄会获得经验、升级解锁能力,你和你的团队也会获得各种成就。
这不是什么噱头,而是基于人类行为心理学的精心设计。当任务被赋予意义和进度反馈时,人的投入度和坚持程度会显著提升。
就像古人说的,"此情可待成追忆,只是当时已惘然"。我们把这种情感体验融入到工具中,让编程不再只是敲代码,而是一段值得回忆的旅程。
Hero 角色系统
Hero 是 HagiCode 游化系统的核心概念。每个 Hero 代表一个 AI 助手,比如 Claude Code 是一个 Hero,Codex 也是一个 Hero。
Hero 的三大槽位
Hero 有三个装备槽位,这个设计其实还挺巧妙的:
- CLI 槽位(主要职业):决定 Hero 的基础能力,比如是 Claude Code 还是 Codex
- Model 槽位(次要职业):决定使用的模型,比如 Claude 4.5 还是 Claude 4.6
- Style 槽位(风格):决定 Hero 的行事风格,比如是"风落策略家"还是"其他风格"
三个槽位的组合可以创造出独特的 Hero 配置。就像游戏里配装一样,你需要根据任务特点选择合适的搭配。毕竟适合自己的才是最好的,这和生活选路差不多,条条大路通罗马,只是有的路好走一点,有的路稍微曲折一点罢了。
Hero 的成长系统
每个 Hero 都有自己的 XP(经验值)和等级:- type HeroProgressionSnapshot = {
- currentLevel: number; // 当前等级
- totalExperience: number; // 总经验值
- currentLevelStartExperience: number; // 当前等级起始经验
- nextLevelExperience: number; // 下一等级所需经验
- experienceProgressPercent: number; // 进度百分比
- remainingExperienceToNextLevel: number; // 距离下一级还需要多少经验
- lastExperienceGain: number; // 最近一次获得的经验
- lastExperienceGainAtUtc?: string | null; // 获得经验的时间
- };
复制代码 等级分为四个阶段,每个阶段的命名都很有代入感:
[code]export const resolveHeroProgressionStage = (level?: number | null): HeroProgressionStage => { const normalizedLevel = Math.max(1, level ?? 1); if (normalizedLevel |