初始提交:三玩法 Web 原型与设计文档
- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试 - 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本 - 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试 - 产品文档、UI 设计规范、各玩法 GDD / HANDOFF - 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
This commit is contained in:
@@ -0,0 +1,386 @@
|
||||
# 玩法三 · 六边一笔
|
||||
|
||||
本文只描述**玩法三**。玩法一、玩法二有自己的目录和 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,让“满盘都在动”的感觉逐关加强。
|
||||
Reference in New Issue
Block a user