Files
NumberSwipe_New/modes/03-hex-walls/docs/GDD.md
T
cabinw 8026e4628d 初始提交:三玩法 Web 原型与设计文档
- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试
- 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本
- 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试
- 产品文档、UI 设计规范、各玩法 GDD / HANDOFF
- 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
2026-09-16 14:30:59 +08:00

387 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 玩法三 · 六边一笔
本文只描述**玩法三**。玩法一、玩法二有自己的目录和 GDD,见仓库 [`docs/PRODUCT.md`](../../../docs/PRODUCT.md)。
在六边形拼板上画一条哈密顿路径。格子之间的边上可以有墙,墙挡住那一条邻接。预先写好的数字,必须刚好在那一步走到。
本玩法是**独立玩法**:六边形 + 边墙,不用矩形大格。墙的价值是把“第一步往哪走”收成推理——看起来相邻的格子,有墙就走不过去。关卡、资源、文案全部原创。
---
## 1. 一句话
在六边形盘上走遍每一格;黄黑条纹的墙贴在两条格子的共用边上,那条路走不通;线索数字必须踩在对应步号上。
## 2. 产品定位
| 项 | 决定 |
|---|---|
| 类型 | 单机、离线、无体力、无计时的逻辑 puzzle |
| 平台 | 手机竖屏。本玩法 V1 先在 `modes/03-hex-walls/web/` 可玩 |
| 单局 | 20–120 秒想,5–12 秒画完 |
| 会话 | 通勤 3 关,睡前 10 关 |
| 对象 | 已经能接受一笔画的人;墙是给“矩形走腻了”的第二层 |
| 付费 | 竖直切面免费无广告 |
和玩法一同属“顺序一笔画”,但几何不同:
| | 玩法一 | 玩法三 |
|---|---|---|
| 格子 | 矩形,可 2×2 只计一步 | 正六边形,一格一步 |
| 邻接 | 四向共边 | 六向共边 |
| 障碍 | 空洞 | 空洞 + **边墙** |
| 代码 | `modes/01-number-stroke` | `modes/03-hex-walls`,禁止互相 import |
不要把墙补进玩法一的后期关。墙是本玩法的主旋钮。
## 3. 核心循环
1. 看盘:线索在哪,墙封了哪几条边,哪一格看起来近其实过不去。
2. 推:从线索往外挤,尤其是被墙封死的第一步。
3. 画:滑到相邻且无墙的未走格,自动填步号。
4. 错了沿原路退,或重开。
5. 全填满且线索全部对上 → 过关。
没有分数。爽感来自“墙把表面的近路掐掉,只剩一条”。
---
## 4. 规则(权威)
### 4.1 盘面
- 格子是点顶(pointy-top)正六边形,用轴坐标 `(q, r)`。
- 每个格是图上一个节点,路径里计 1 步。没有大格。
- 单位格要么属于恰好一个六边形,要么是空洞。
- 盘面可不规则。
轴坐标邻接(未考虑墙):
```
(q+1, r), (q-1, r), (q, r+1), (q, r-1), (q+1, r-1), (q-1, r+1)
```
### 4.2 墙
墙是**无向边**,贴在两个相邻格的共用边上,画成黄黑斜纹警示条。
- 有墙的两格视为**不相邻**。其它邻接不受影响。
- 墙不占格,不能走在墙上。
- 同一对格最多一堵墙。
- 墙必须画在真实共用边上。不能“对角墙”。
这是本玩法相对玩法一多出来的唯一新原语。
### 4.3 路径
目标:在「去墙之后的格图」上找一条哈密顿路径。
- 每个格恰好一次。
- 只能走到相邻、无墙、尚未走过的格。
- 第 k 个格显示数字 k(从 1 起)。
- 不能分叉、不能跳、不能穿墙。
### 4.4 线索格
部分格预先写了正整数 `c`,带描边。
- 走到该格时步号必须等于 `c`。
- 可以没有 `1`(起点未知)。教学前 8 关必须有 `1`。
- 线索互不相同,`1 ≤ c ≤ N`。
- 可以没有 `N`。
### 4.5 对错
允许暂时画错:
- 踩到线索但步号 ≠ `c`:该格冲突态(红底),显示当前步号。
- 冲突不打断手势。
- **过关**:所有格走过,且所有线索步号正确。
- 无失败弹窗。穿墙或对角滑:忽略。
### 4.6 内容铁律
发布前求解器必须断言:
1. 去墙后的图连通。
2. 恰好 1 条哈密顿路径满足全部线索。
3. 线索尽量少。教学关可以多给。
若去掉全部墙后解变得不唯一,说明墙在干活,这关才算合格的“墙关”。第 3 关起,每关至少 1 堵墙,且去掉墙会破坏唯一性。
---
## 5. 交互
单指。和玩法一同一套手感,只是命中的是六边形、且要检查墙。
| 手势 | 行为 |
|---|---|
| 点合法起点 | 该格成为第 1 步 |
| 滑向相邻、无墙、未走格 | 追加 |
| 滑向有墙的邻居 | 忽略(可在墙上闪一下) |
| 滑回上一格 | 撤销 |
| 滑到不相邻 / 已走且非上一格 | 忽略 |
| 松手 | 保留路径,可从末端继续 |
合法起点:有线索 `1` 则只能从它起手;否则任意格。
按钮:重开、提示、菜单(本玩法选关 / 回壳)。顶栏:`{pack}-{index}`、剩余格、菜单。
输入状态机与玩法一相同:Empty → Drawing → Idle → Cleared。实现时不要 import 玩法一,允许各写一份。
---
## 6. 反馈与手感
| 事件 | 反馈 |
|---|---|
| 追加一步 | 六边形 80ms 弹,共用边拉一条短线 |
| 撞墙 | 墙闪白 100ms,短振动,不追加 |
| 线索步号正确 | 描边闪白 |
| 冲突 | 红底 |
| 过关 | 路径色提高,短线顺次扫过 |
未走:中灰。已走:蓝紫。墙:黄黑斜纹,对比足够,不靠颜色当唯一信息(色弱可把墙改成粗黑 + 缺口)。背景白。
---
## 7. 关卡语言
一次只加一个旋钮。
| 旋钮 | 作用 | 何时引入 |
|---|---|---|
| 格数 N | 6–8 教学,9–14 常规,15–20 后期 | 全程 |
| 墙的条数 | 1 堵教规则,2–4 堵做推理 | 第 3 关 |
| 墙贴在线索旁 | 第一步往往只剩一个方向 | 第 4 关 |
| 空洞 | 和墙叠加,近路更假 | 第 6 关 |
| 中段线索 | 不只靠起点 | 第 5 关 |
| 无线索 1 | 起点未知 | 第 13 关之后 |
不做:矩形大格、斜穿、传送、限时。大格是玩法一的旋钮,不要混进来。
### 7.1 教学 8 关(必须手做)
1-1 到 1-4 的坐标在 `levels/pack-1-tutorial.json`。
| 关 | 教什么 |
|---|---|
| 1-1 | 六边形、滑动、自动出数字。无墙。3 格 |
| 1-2 | 必须走完。5 格,标 1 和 5 |
| 1-3 | 第一堵墙:看起来相邻,滑不过去,必须绕 |
| 1-4 | 墙贴在 1 旁边,第一步不是“随便挑邻居” |
| 1-5 | 中段线索 |
| 1-6 | 两堵墙 + 一个空洞 |
| 1-7 | 先想再画,错了要退 |
| 1-8 | 综合:约 12 格、3 堵墙、3 个线索 |
1-3 是关键:过不了“墙是边不是格”,后面全废。
### 7.2 结构
一包 8 关。V1:教学 8 + 3 包 × 8 = **32 关**。线性解锁。
### 7.3 规则样例
规则样例直接用 `levels/pack-1-tutorial.json`:1-3 演示“墙是边不是格”(两格共边却被墙封住,看起来相邻,滑不过去,必须绕),1-4 演示“墙贴在线索旁,第一步只剩一个方向”。全部关卡由求解器断言唯一解且墙参与唯一性(§4.6)。
---
## 8. 生成器与求解器
教学关手做。第 9 关起可生成,人要过一眼。
求解器:
- 输入:六边形列表 + 墙边列表 + 线索。
- 邻接 = 轴坐标六邻接减去墙。
- 回溯哈密顿路径,线索处剪枝。
- `N ≤ 20`。发布条件 `paths.length === 1`。
- 额外检查:删掉所有墙之后 `paths.length !== 1`(墙必须改变解集合)。
生成:
1. 铺一块连通的六边形聚落,可挖洞。
2. 随机一条哈密顿路径当作者解。
3. 在**不是作者解所用的边**上插 1~3 堵墙。
4. 加 2~3 个线索直到唯一。
5. 跑“去墙不唯一”检查。失败则换墙。
关卡文件:
```json
{
"id": "1-3",
"pack": 1,
"index": 3,
"orientation": "pointy",
"cells": [
{ "id": "a", "q": 0, "r": 0, "clue": 1 },
{ "id": "b", "q": 1, "r": 0 },
{ "id": "c", "q": 0, "r": 1 }
],
"walls": [
["a", "b"]
]
}
```
`walls` 是格 id 对。求解器不写进 JSON。
---
## 9. 界面与流程
```
(壳:选玩法)→ 本玩法选关 → 对局 → 过关 → 下一关
↘ 菜单:关卡列表 / 回壳
```
对局层:顶栏关号与剩余格,中间六边形盘(按短边缩放),底栏重开 / 提示。过关短动画后自动下一关。
1-1 一行:“从一个数字滑到旁边的格子”。1-3 一行:“条纹是墙,绕开它”。之后无文案。
---
## 10. 提示、存档
提示:
- 无路径:指出合法起点。
- 路径是唯一解前缀:指出下一步。
- 已偏离:高亮分叉点,不继续给错下一步。
- 竖直切面无限次。
存档键前缀 `mode:03-hex-walls`。`clearedId[]`、`currentId`。不存半途路径。
---
## 11. 设计边界
V1 只做主规则(§4)。明确不做:
- 矩形大格(玩法一的旋钮)
- 矩形 + 墙、斜穿、传送、限时
- 计分
几何锁定为六边形,墙是边不是格。关卡、资源、文案全部原创,不使用第三方题库或素材。
---
## 12. 技术
全部落在 `modes/03-hex-walls/`。
禁止:
- import 玩法一的 Cell / 四向邻接 / 矩形碰撞
- 把墙做成“第三种格子”
| 项 | 决定 |
|---|---|
| 竖直切面 | `web/` 单页 |
| 坐标 | 轴坐标 pointy-top |
| 求解器 | `tools/solver.ts`,只服务本玩法 |
| 关卡 | `levels/*.json` |
模块:`model`(Hex、Wall、Path)、`rules`、`input`、`solver`、`view`。
---
## 13. 竖直切面
1. 1-1、1-2 无墙可过。
2. 1-3 直滑进墙无效,绕开后能过。
3. 1-4 有线索 1 时点别的格起手无效;墙让第一步只剩一个方向。
4. 冲突、撤销、重开与玩法一同样稳。
5. 求解器对 VS 关断言唯一解,且去墙后不唯一(1-3 起)。
6. 提示在偏离时拉回分叉。
---
## 14. 里程碑
| 阶段 | 交付 |
|---|---|
| M0 | 本 GDD 锁定 |
| M1 | 规则 + 求解器 + 1-1~1-4 可玩 |
| M2 | 1-1~1-8 + 存档 |
| M3 | 再 24 关 + 选关 |
| M4 | 迁 Cocos 本玩法场景 |
---
## 15. 关键决定
1. **独立玩法,不是玩法一的 DLC。** 六边形模型和边墙都住在本目录。
2. **墙是边,不是格。** 穿墙 = 那条邻接不存在。
3. **解唯一,且墙必须参与唯一性。**
4. **允许画错,随时撤回。**
5. **无大格。** 大格留给玩法一。
6. **先 Web,再 Cocos。**
---
## 16. 验收
- 没玩过的人在 1-3 结束前理解墙。
- 1-4 开始出现停顿,不是闭眼滑。
- 任意关关闭提示仍可人解。
- 撞墙 10 次不误走、不穿模。
---
## 17. 已关闭的问题
- 要不要合并进玩法一?不要。
- 要不要矩形 + 墙?不要。本玩法锁六边。
- 要不要计分?不要。
## 18. 留给实现的缺口
- 对外名称是否就用「六边一笔 / Hex Stroke」。
- 墙的最终画法(斜纹宽度、是否要缺口给色弱)。
- M3 关是手做还是生成后人工改,看 M2。
---
## 19. 附录 A · 转墙(实验机制,2026-09-15 加入)
### A.1 设计铁律:手指就是笔尖
路径的末端永远在指尖下面;手指走过哪些格,路径就是哪些格。任何让末端离开指尖的机制(滑行、传送、跳格、自动延伸)一律不做。新机制只能改三样东西:哪一步合法、数字怎么数、过关条件是什么。
### A.2 规则
- 六边形网格上每个顶点交汇三条边,互成 120°。转墙固定在一个顶点上,任意时刻占其中一条边,画法与静态墙相同,只在轴心那一端加一个圆点。
- 每走一格(含起手那一格),所有转墙同拍顺时针转 120°。已走 t 格时,墙在第 `(phase + t) mod 3` 条边上。
- 判定能否从末端走到邻格,用的是**出发前**的位置;走完再转。撤销一步则倒转回去。状态完全由步号推出,不需要额外存档。
- 转到盘外或空洞的边上时,墙暂时不挡任何东西。
- 转墙不得与静态墙重叠;周围至少要有两条盘上的边。
### A.3 玩家体验
玩家不仅要估计路线,还要估计到达某条边时墙在哪。线索数字给出步号,步号 mod 3 就是墙的位置,所以线索和转墙天然互相配合:为了让某一步“刚好开着”,路线要多绕或少绕一格。
### A.4 内容铁律(在 §4.6 之上追加)
每个转墙必须同时满足:
1. 去掉它,解不再唯一。
2. 把它换成钉在任意一条候选边上的静态墙,解都不再唯一(保证“会转”参与推理,而不是随便一堵墙就能替代)。
同一顶点只能放一个转墙;两个转墙可以共用一条候选边。实验包里最多放到 4 个转墙(19 格),正式包按试玩结果定上限。
### A.5 关卡文件
```json
"spinners": [{ "cell": "c", "corner": 0, "phase": 1 }]
```
`corner` 是该格第几个角(从 30° 起顺时针 0..5),`phase` 是空盘时墙在第几条候选边。候选边顺时针编号:0 = 背离该格的那条边,1 = 该格与顺时针下一邻格,2 = 该格与上一邻格。
### A.6 实验包
`levels/pack-2-spinner.json`,9 关:2-1 教规则(起手后墙正好挡住直觉的第一步),2-2 用中段线索算拍子,2-3 静态墙 + 转墙综合;2-4 起转墙数逐步加到 4,格数 7→19,让“满盘都在动”的感觉逐关加强。