大家好!刚想分享我昨天发布的全新 vibecoded 项目——22CHAMPS。这款项目灵感来自上周 X 上走红的 All22Pokemon,由 ColeThereum 创作,是一款宝可梦 × 足球风格的选秀。我觉得很有趣,想尝试做类似的东西,但针对《英雄联盟》英雄,并加入自己的风格。
项目
在线玩: 22champs.com(免费,无广告,无需账号)
你在一支足球队上选拔《英雄联盟》英雄,全部 22 名首发分别担任进攻和防守,然后进行 17 场比赛的赛季。
每一次选拔会随机生成一个 region(地区)和一个 role(位置),你只能从符合条件的英雄中选择。邻近的队友如果共享同一位置或同一地区,就会建立化学羁绊,39 条剧情羁绊(盖瑞 + 丽兹、夏雅 + 拉坎)会相互增强。三种模式:每日挑战(所有人拥有相同的随机结果,一次性完成)、单人选秀,以及与好友进行的实时蛇形 选秀。
游戏系统工作方式
将《英雄联盟》英雄转化为足球运动员
每张卡片拥有六项属性:
- Power(PWR)
- Toughness(TGH)
- Speed(SPD)
- Size(SIZ)
- Hands(HND)
- Range(RNG)
属性基于 Riot 为每位英雄提供的 1–3 评分(客户端中的伤害/韧性/控制/机动性/实用性条),经过基础属性、体型以及像 Juke 或 Deep Ball 等技能特性的细化,再与整体阵容进行比较。每个位置由 2–5 项属性组合而成。射手侧重 Speed 与 Hands,前锋侧重 Size 与 Toughness。因此,每位英雄在每个位置上都有评分。该位置的最高评分为 95,只有通过化学羁绊才能提升至 99。
将 Riot 真实物品数据转化为卡片
脚本会直接从 Riot 的 Data Dragon 拉取《英雄联盟》物品的商店属性:所有 Summoner’s Rift 与 Arena 的完整物品,以及经典靴子。每项《英雄联盟》属性对应 22CHAMPS 卡片上对应的属性:
- 攻击伤害、法术伤害和暴击伤害 → Power
- 攻击速度和暴击率 → Hands
- 防御、魔抗和坚韧 → Toughness
- 生命值 → Size
- 移动速度和法术加速 → Speed
- Range(基本攻击范围)并非商店属性,只有三件被动能延长范围的物品(Diamond-Tipped Spear、Rapid Firecannon、Hexoptics C44)会人工分配 Range 点,越可靠的范围提升越多。
法力值和蓝条在足球中没有意义,因此被移除。
每件物品拥有相同的 15 卡片点 预算,分配方式取决于其在《英雄联盟》中每个属性的金值。例如:Infinity Edge 拥有 75 点攻击伤害、25% 暴击率和 30% 暴击伤害。按金值估算,约为三分之二的属性归为 Power,一分之四归为 Hands,因此卡片上表现为 +11 Power,+4 Hands。
Warmog's Armor 几乎全部由生命值构成,因此表现为 +15 Size。每件物品的预算相同,没有哪件严格更好,它们只是让英雄在不同方向发展。Arena 的 Prismatic 物品获得 20 点,出现频率更低。
靴子是例外。几乎所有靴子的金值都来自移动速度,公式让每双靴子几乎相同。我根据它们在《英雄联盟》中的作用手动设定:狂战者之靴为攻击速度提供 Hands,板甲鞋增加 Toughness 以提升护甲,以此类推。
化学,FIFA Ultimate Team 风格
这里我尝试加入更多趣味和多样性。相邻位置之间的羁绊价值不同:共享位置得 0.5 点,共享地区得 1 点,两者皆得 1.5 点,剧情羁绊得 2 点。这些羁绊以绿色菱形表示。玩家的羁绊总数在 0–3 之间,每个菱形提升其位置最重要的属性。
比如,如果你把 Lux 放在 WR(宽 receiver)位置,WR 通常侧重 SPD、HND 和 RNG,若 Lux 拥有 3 级化学羁绊,则 SPD、HND、RNG 各提升 +6。由于只有五个位置,邻位会一直共享一个位置,所以位置羁绊只计 0.5 分。
工具
- Claude Code 在 VS Code 中编写了几乎所有代码
- Next.js 16 在 Vercel 上:每次推送到 main 分支都会部署
- Supabase 用于多人选秀房间
- PostHog 用于分析,无需 cookie,因此没有弹窗
- Vitest 用于游戏逻辑,Playwright 用于截图和录制游戏过程,Remotion 用于制作预告片
我的工作流程
我已经有 2–3 年使用 AI 开发游戏的经验,而这次是第一次真正利用语音转文本进行提示和规划。以一种奇怪的方式,它让我更高效地把粗略的构想说出来,随后迭代更加聚焦。说不清原因,但感觉通过语音表达的构想比文本提示更清晰。
- 我负责决定,Claude 负责编写代码。 我描述想要实现的内容和原因,审查结果并给出反馈。大部分输入是设计和平衡决策,而非代码。
- 截图是回顾循环。 对 UI 工作而言,Claude 会在本地构建上运行 Playwright 并对多种分辨率(从 1250×910 的笔记本到我的 2560×1440 显示器)进行页面截图。很多反馈直接是“在 1331×844 时 How it works 面板下方掉到场地外,请修复”。
- 决定写入记忆文件。 诸如“位置权重仅影响位置”等,或“上线后每日中午不再改动”这类内容会被记录下来,防止新会话覆盖之前的设定。
- 测试保护模拟。 约 230 条 Vitest 测试,包括模拟游戏的快照测试,确保平衡调整不会悄无声息改变结果。
- 小幅提交。 12 天内约 160 次提交,每次都是一个可以在浏览器中直接观察的单一改动。
建立洞察
每日挑战对所有人相同,且无需后端。 每日的随机结果由基于日数的随机数生成器种子决定,因此所有玩家都获得相同的游戏,服务器无需存储任何数据:
const roll = rng(hash(`daily-${dayNumber}`));
保持每日公平。 在每日上线前,其 CPU 队伍会被播放数十次模拟选秀。如果获胜率不在 25–75% 范围内,则整个游戏会重新生成。
通过审计而非直觉进行平衡。 我让 Claude 模拟数千次选秀,发现有些英雄的随机结果根本无法发挥作用,且跑动/传球失衡导致某种进攻方式完全无效。上线后,真实选秀数据会通过 PostHog 私有平衡页面进行监测。
布局比游戏逻辑更难。 将整个选秀过程在不滚动的情况下适配所有桌面尺寸,耗费最多的回顾。两条经验教训:CSS contain: size 能阻止侧边栏撑开页面,而移动 CSS 导入可能悄然改变哪些样式生效,因此每次重构后都会检查截图。
预告片也是代码。 游戏过程由带有随机种子的 Playwright 脚本记录,每次录制结果都相同。Remotion 会根据音乐节拍剪辑,因此更新后重新录制会自动重新编辑。
非官方粉丝项目,未经 Riot 正式授权。我很想得到反馈,尤其是前 30 秒是否对从未见过该项目的人来说是否易懂。欢迎分享你的结果!
评论 (0)