谢夏戈 @ xiexiage.com

立项

Sep 1

贪吃蛇的玩法早就定了,为什么还要立项?因为做到一半你一定会想加东西——"要不要加道具?加穿墙?加皮肤?"。「不做什么」现在不写死,之后就没有任何东西能拦住你。 小鸟能按时做完,就是因为一开始写死了"无关卡、无道具、无皮肤"。

立项表

这张表就是这个游戏的全部规则,代码只是把它翻译成 Godot 听得懂的话:

内容
核心玩法控制蛇移动,吃到普通食物变长 +1 分;吃到星星变长 +2 分
食物规则普通食物每 3 秒长一个,场上最多 3 个,吃掉不立刻补。星星每 12 秒一颗,会发光,5 秒没人吃就消失
开局设置撞墙模式 / 穿墙模式,开始界面用 ◀ ▶ 左右选
胜负撞到自己 → 结束;撞墙模式下撞墙 → 结束;穿墙模式下从对面出来
操作键盘(方向键 / WASD / Esc)和手柄(十字键 / 左摇杆 / Start),全程不碰鼠标也能玩完
【不做】无关卡、无第二种道具、无联机、无排行榜、无像素美术(纯色方块)、无背景音乐
完成标准菜单选模式 → 游戏 → 暂停/继续 → 撞死 → 看分数和最高分 → 重开 / 回菜单;只用手柄能走完;导出 Web

为什么食物要"按时间长、吃掉不补"

经典贪吃蛇里食物永远只有一个,玩家只有一件事:去吃它。改成按时间生成之后,场上可能有 0~3 个食物、一颗随时会消失的星星——玩家要做选择:去远的那个?等近处长出来?绕过去抢星星值不值?

这些选择就是"玩法"。数据结构只多了一个数组,体验完全不一样。这是我在这个项目里最满意的一个决定。

实体清单:想清楚再动手

小鸟那次的真正根因,不是"忘了配碰撞层",是一上来就写代码、没先问"谁要检测谁",最后只能用 body.name 打补丁。这次先拿纸笔回答两个问题:

A:这个游戏里有哪些「东西」? → 蛇头 · 蛇身 · 普通食物(0~3 个)· 星星(0 或 1 个,会过期)· 墙

B:谁碰到谁会怎样?用什么判定?

碰到谁结果用什么判定
蛇头墙(撞墙模式)坐标超出 0~格数-1?→ 数字比较
蛇头墙(穿墙模式)从对面出来坐标绕一圈 → 取余
蛇头蛇身坐标在数组里?→ in
蛇头普通食物变长 +1坐标在食物数组里?→ in
蛇头星星变长 +2两个坐标相等?→ ==
星星时间5 秒后消失Timer(One Shot)
棋盘时间每 3 秒长一个食物Timer(重复)

填完,结论自己就出来了:

  • 前五行全是坐标运算 → 不需要物理引擎,不用配碰撞层,不用 Area2D
  • 后两行多出来一个对手叫"时间" → 答案是 Timer

什么时候才需要物理引擎?当表里出现"两个不规则形状重叠了吗""它会被挡住吗"这种回答。下一个需要它的游戏(打砖块)填这张表时答案会变成"形状重叠"——那时再配图层,就知道自己在配什么。

这一步的价值不是"配图层",是"想清楚再动手"。很多游戏(网格类、回合制、卡牌)根本用不到物理引擎,硬配图层只是白做功。

下一章开 Godot,把这些数变成项目设置。

2023-PRESENT © 谢夏戈