立项
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,把这些数变成项目设置。