nav: 三级导航分页结构 + 中国地区索引
- 02-game-design 地图结构重写:洲→国家→城市,3x3棋盘分页 - 中国 40 城按 8 地区分组(华北/东北/华东/华中/华南/西南/西北/港澳) - 导航索引数据:continents/index + asia + regions/china + pagination工具 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,38 +75,160 @@
|
||||
|
||||
## 2. 地图结构
|
||||
|
||||
### 2.1 导航层级(MVP 简化为二级)
|
||||
### 2.1 导航层级
|
||||
|
||||
```
|
||||
MVP 首版:直接进入亚洲城市页(跳过洲选择页)
|
||||
城市选择(3x3 棋盘) → 城市关卡(单局游戏)
|
||||
|
||||
V1.1 扩展第二个洲后:
|
||||
洲选择(3x3 棋盘) → 城市选择(3x3 棋盘) → 城市关卡
|
||||
洲(3x3 棋盘)
|
||||
└── 国家(3x3 棋盘,超过 9 国分页)
|
||||
└── 城市(3x3 棋盘,超过 9 城分页)
|
||||
└── 关卡(单局游戏)
|
||||
```
|
||||
|
||||
预留洲选择页的代码入口但 MVP 不显示。
|
||||
中国因城市数量多(40 城),额外增加"地区"层级:
|
||||
|
||||
### 2.2 主页面设计
|
||||
```
|
||||
亚洲 → 中国 → 地区(3x3)→ 城市(3x3)→ 关卡
|
||||
亚洲 → 日本 → 城市(3x3)→ 关卡
|
||||
```
|
||||
|
||||
- MVP 直接显示亚洲城市 3x3 棋盘,顶部标题"亚洲"
|
||||
- V1.1 扩展第二个洲后再开启洲选择页
|
||||
### 2.2 洲选择页(第 1 级)
|
||||
|
||||
### 2.3 洲内页面设计
|
||||
1 页,3×3 棋盘:
|
||||
|
||||
- 3x3 棋盘布局,每格代表一个城市
|
||||
- 城市封面:特色猫猫头像 + 城市名
|
||||
- 已通关城市:猫猫头像点亮 + 通关星级
|
||||
- 未解锁城市:灰色剪影 + 锁图标
|
||||
- 解锁规则:顺序解锁(通关前一个解锁下一个),第 1 个城市默认解锁
|
||||
```
|
||||
┌────────┬────────┬────────┐
|
||||
│ 亚洲 │ 欧洲 │ 北美洲 │
|
||||
├────────┼────────┼────────┤
|
||||
│ 南美洲 │ 非洲 │ 大洋洲 │
|
||||
├────────┼────────┼────────┤
|
||||
│ │ │ │
|
||||
└────────┴────────┴────────┘
|
||||
```
|
||||
|
||||
### 2.4 城市关卡结构
|
||||
6 个洲,3 个空位留给未来扩展。MVP 只开放亚洲,其余显示锁定 + "即将开放"。
|
||||
|
||||
每个城市包含 **6 个基础关卡**,全部通关才算"通关该城市"。
|
||||
每个洲的封面:洲标志性图案 + 解锁进度(如"6/70 城市已解锁")。
|
||||
|
||||
- 每关使用该城市 12-15 个特色元素中的 8-12 个
|
||||
- 难度递增:关 1 用 6 种元素各 3 个,关 6 用 10 种元素,各 3 或 6 个(混合配置) + 更深堆叠
|
||||
- 通关后获得该城市的猫猫收集卡
|
||||
### 2.3 国家选择页(第 2 级)
|
||||
|
||||
#### 亚洲 — 2 页
|
||||
|
||||
Page 1:
|
||||
```
|
||||
┌────────┬────────┬────────┐
|
||||
│ 中国 │ 日本 │ 韩国 │
|
||||
├────────┼────────┼────────┤
|
||||
│ 泰国 │ 新加坡 │ 越南 │
|
||||
├────────┼────────┼────────┤
|
||||
│马来西亚│印度尼西亚│ 菲律宾│
|
||||
└────────┴────────┴────────┘
|
||||
```
|
||||
|
||||
Page 2:
|
||||
```
|
||||
┌────────┬────────┬────────┐
|
||||
│ 印度 │ 阿联酋 │ 土耳其 │
|
||||
├────────┼────────┼────────┤
|
||||
│ 以色列 │ 尼泊尔 │ 柬埔寨 │
|
||||
├────────┼────────┼────────┤
|
||||
│斯里兰卡│ 缅甸 │ 蒙古 │
|
||||
└────────┴────────┴────────┘
|
||||
```
|
||||
|
||||
#### 欧洲 — 2 页
|
||||
|
||||
Page 1:
|
||||
```
|
||||
法国、英国、意大利、西班牙、德国、荷兰、瑞士、奥地利、捷克
|
||||
```
|
||||
|
||||
Page 2:
|
||||
```
|
||||
希腊、俄罗斯、葡萄牙、挪威、瑞典、丹麦、芬兰、冰岛、匈牙利
|
||||
```
|
||||
|
||||
#### 北美洲 — 1 页
|
||||
```
|
||||
美国、加拿大、墨西哥 + 6 空位
|
||||
```
|
||||
|
||||
#### 南美洲 — 1 页
|
||||
```
|
||||
巴西、阿根廷、秘鲁、智利、哥伦比亚 + 4 空位
|
||||
```
|
||||
|
||||
#### 非洲 — 1 页
|
||||
```
|
||||
埃及、南非、摩洛哥、肯尼亚 + 5 空位
|
||||
```
|
||||
|
||||
#### 大洋洲 — 1 页
|
||||
```
|
||||
澳大利亚、新西兰 + 7 空位
|
||||
```
|
||||
|
||||
### 2.4 中国地区选择页(第 3 级,仅中国)
|
||||
|
||||
中国 40 个城市按地区分组,1 页 3×3:
|
||||
|
||||
```
|
||||
┌────────┬────────┬────────┐
|
||||
│ 华北 │ 东北 │ 华东 │
|
||||
├────────┼────────┼────────┤
|
||||
│ 华中 │ 华南 │ 西南 │
|
||||
├────────┼────────┼────────┤
|
||||
│ 西北 │ 港澳 │ │
|
||||
└────────┴────────┴────────┘
|
||||
```
|
||||
|
||||
各地区包含城市:
|
||||
|
||||
| 地区 | 城市 | 数量 | 页数 |
|
||||
|------|------|------|------|
|
||||
| 华北 | 北京、天津、石家庄、太原、呼和浩特 | 5 | 1 |
|
||||
| 东北 | 沈阳、长春、哈尔滨、大连 | 4 | 1 |
|
||||
| 华东 | 上海、南京、杭州、合肥、福州、南昌、济南、苏州、厦门、青岛、宁波 | 11 | 2 |
|
||||
| 华中 | 郑州、武汉、长沙 | 3 | 1 |
|
||||
| 华南 | 广州、深圳、南宁、海口、三亚 | 5 | 1 |
|
||||
| 西南 | 成都、重庆、贵阳、昆明、拉萨 | 5 | 1 |
|
||||
| 西北 | 西安、兰州、西宁、银川、乌鲁木齐 | 5 | 1 |
|
||||
| 港澳 | 香港、澳门 | 2 | 1 |
|
||||
|
||||
### 2.5 城市选择页(第 3/4 级)
|
||||
|
||||
#### 其他国家(非中国)— 直接展示城市
|
||||
|
||||
| 国家 | 城市数 | 页数 |
|
||||
|------|--------|------|
|
||||
| 日本 | 4(东京、大阪、京都、札幌) | 1 |
|
||||
| 韩国 | 3(首尔、釜山、济州) | 1 |
|
||||
| 泰国 | 3(曼谷、清迈、普吉) | 1 |
|
||||
| 美国 | 7(纽约、洛杉矶、旧金山、拉斯维加斯、华盛顿、芝加哥、迈阿密) | 1 |
|
||||
| 意大利 | 4(罗马、米兰、威尼斯、佛罗伦萨) | 1 |
|
||||
| 其他国家 | 1-3 | 1 |
|
||||
|
||||
所有国家的城市数均 ≤ 9,无需分页(除华东 11 城需 2 页外)。
|
||||
|
||||
### 2.6 城市封面设计
|
||||
|
||||
每个格子显示:
|
||||
- 该城市/国家/洲的特色猫猫头像(已解锁:彩色,未解锁:灰色剪影)
|
||||
- 名称(中文)
|
||||
- 进度信息(已解锁:"X/6 关",未解锁:"🔒")
|
||||
|
||||
### 2.7 分页交互
|
||||
|
||||
- 左右滑动翻页,底部圆点指示器
|
||||
- 首次进入默认第 1 页
|
||||
- 翻页动画 0.3s 弹性过渡
|
||||
|
||||
### 2.8 解锁规则
|
||||
|
||||
- 同一层级内顺序解锁(通关前一个解锁下一个)
|
||||
- 第一个项目默认解锁
|
||||
- 跨层级:通关一个国家所有城市后,解锁下一个国家
|
||||
- 中国地区内:通关华北所有城市后解锁东北,以此类推
|
||||
- MVP 只开放亚洲洲,亚洲内只开放中国(北京)和已有 MVP 城市
|
||||
|
||||
---
|
||||
|
||||
|
||||
32
js/content/continents/asia.js
Normal file
32
js/content/continents/asia.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 亚洲国家列表 — 16 国,分 2 页
|
||||
|
||||
export const asiaCountries = [
|
||||
// Page 1
|
||||
{ id: 'china', name: '中国', nameEn: 'China', sortOrder: 1, themeColor: '#CC2936', hasRegions: true, totalCities: 40 },
|
||||
{ id: 'japan', name: '日本', nameEn: 'Japan', sortOrder: 2, themeColor: '#E84057', hasRegions: false, totalCities: 4 },
|
||||
{ id: 'korea', name: '韩国', nameEn: 'South Korea', sortOrder: 3, themeColor: '#4A90D9', hasRegions: false, totalCities: 3 },
|
||||
{ id: 'thailand', name: '泰国', nameEn: 'Thailand', sortOrder: 4, themeColor: '#FFB347', hasRegions: false, totalCities: 3 },
|
||||
{ id: 'singapore', name: '新加坡', nameEn: 'Singapore', sortOrder: 5, themeColor: '#00A896', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'vietnam', name: '越南', nameEn: 'Vietnam', sortOrder: 6, themeColor: '#E74C3C', hasRegions: false, totalCities: 2 },
|
||||
{ id: 'malaysia', name: '马来西亚', nameEn: 'Malaysia', sortOrder: 7, themeColor: '#3498DB', hasRegions: false, totalCities: 2 },
|
||||
{ id: 'indonesia', name: '印度尼西亚', nameEn: 'Indonesia', sortOrder: 8, themeColor: '#E67E22', hasRegions: false, totalCities: 2 },
|
||||
{ id: 'philippines', name: '菲律宾', nameEn: 'Philippines', sortOrder: 9, themeColor: '#2ECC71', hasRegions: false, totalCities: 1 },
|
||||
// Page 2
|
||||
{ id: 'india', name: '印度', nameEn: 'India', sortOrder: 10, themeColor: '#FF9933', hasRegions: false, totalCities: 2 },
|
||||
{ id: 'uae', name: '阿联酋', nameEn: 'UAE', sortOrder: 11, themeColor: '#C0A062', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'turkey', name: '土耳其', nameEn: 'Turkey', sortOrder: 12, themeColor: '#1A5276', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'israel', name: '以色列', nameEn: 'Israel', sortOrder: 13, themeColor: '#5DADE2', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'nepal', name: '尼泊尔', nameEn: 'Nepal', sortOrder: 14, themeColor: '#DC143C', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'cambodia', name: '柬埔寨', nameEn: 'Cambodia', sortOrder: 15, themeColor: '#1E8449', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'sri_lanka', name: '斯里兰卡', nameEn: 'Sri Lanka', sortOrder: 16, themeColor: '#8E44AD', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'myanmar', name: '缅甸', nameEn: 'Myanmar', sortOrder: 17, themeColor: '#F4D03F', hasRegions: false, totalCities: 1 },
|
||||
{ id: 'mongolia', name: '蒙古', nameEn: 'Mongolia', sortOrder: 18, themeColor: '#2980B9', hasRegions: false, totalCities: 1 },
|
||||
]
|
||||
|
||||
// 分页:2 页
|
||||
export const asiaCountryPages = [
|
||||
asiaCountries.slice(0, 9),
|
||||
asiaCountries.slice(9),
|
||||
]
|
||||
|
||||
export default asiaCountries
|
||||
16
js/content/continents/index.js
Normal file
16
js/content/continents/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
// 洲索引 — 3x3 棋盘第 1 级
|
||||
// 每页 9 格,当前 6 个洲 + 3 空位
|
||||
|
||||
export const continents = [
|
||||
{ id: 'asia', name: '亚洲', nameEn: 'Asia', sortOrder: 1, themeColor: '#FF6B6B', icon: '🏯', totalCities: 70 },
|
||||
{ id: 'europe', name: '欧洲', nameEn: 'Europe', sortOrder: 2, themeColor: '#6B8CFF', icon: '🏰', totalCities: 28 },
|
||||
{ id: 'north_america', name: '北美洲', nameEn: 'North America', sortOrder: 3, themeColor: '#FFB347', icon: '🗽', totalCities: 12 },
|
||||
{ id: 'south_america', name: '南美洲', nameEn: 'South America', sortOrder: 4, themeColor: '#4ECDC4', icon: '🌴', totalCities: 7 },
|
||||
{ id: 'africa', name: '非洲', nameEn: 'Africa', sortOrder: 5, themeColor: '#F7DC6F', icon: '🦁', totalCities: 5 },
|
||||
{ id: 'oceania', name: '大洋洲', nameEn: 'Oceania', sortOrder: 6, themeColor: '#82E0AA', icon: '🦘', totalCities: 4 },
|
||||
]
|
||||
|
||||
// 分页:1 页(6 项 ≤ 9)
|
||||
export const continentPages = [continents]
|
||||
|
||||
export default continents
|
||||
7
js/content/countries/japan.js
Normal file
7
js/content/countries/japan.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export const japanCities = {
|
||||
countryId: 'japan',
|
||||
cityIds: ['tokyo', 'osaka', 'kyoto', 'sapporo'],
|
||||
// 4 城市,1 页
|
||||
}
|
||||
|
||||
export default japanCities
|
||||
73
js/content/regions/china.js
Normal file
73
js/content/regions/china.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// 中国地区列表 — 8 个地区,1 页
|
||||
|
||||
export const chinaRegions = [
|
||||
{
|
||||
id: 'north_china',
|
||||
name: '华北',
|
||||
nameEn: 'North China',
|
||||
sortOrder: 1,
|
||||
themeColor: '#CC2936',
|
||||
cityIds: ['beijing', 'tianjin', 'shijiazhuang', 'taiyuan', 'hohhot'],
|
||||
},
|
||||
{
|
||||
id: 'northeast',
|
||||
name: '东北',
|
||||
nameEn: 'Northeast',
|
||||
sortOrder: 2,
|
||||
themeColor: '#5DADE2',
|
||||
cityIds: ['shenyang', 'changchun', 'harbin', 'dalian'],
|
||||
},
|
||||
{
|
||||
id: 'east_china',
|
||||
name: '华东',
|
||||
nameEn: 'East China',
|
||||
sortOrder: 3,
|
||||
themeColor: '#2ECC71',
|
||||
cityIds: ['shanghai', 'nanjing', 'hangzhou', 'hefei', 'fuzhou', 'nanchang', 'jinan', 'suzhou', 'xiamen', 'qingdao', 'ningbo'],
|
||||
},
|
||||
{
|
||||
id: 'central_china',
|
||||
name: '华中',
|
||||
nameEn: 'Central China',
|
||||
sortOrder: 4,
|
||||
themeColor: '#E67E22',
|
||||
cityIds: ['zhengzhou', 'wuhan', 'changsha'],
|
||||
},
|
||||
{
|
||||
id: 'south_china',
|
||||
name: '华南',
|
||||
nameEn: 'South China',
|
||||
sortOrder: 5,
|
||||
themeColor: '#FF6B6B',
|
||||
cityIds: ['guangzhou', 'shenzhen', 'nanning', 'haikou', 'sanya'],
|
||||
},
|
||||
{
|
||||
id: 'southwest',
|
||||
name: '西南',
|
||||
nameEn: 'Southwest',
|
||||
sortOrder: 6,
|
||||
themeColor: '#9B59B6',
|
||||
cityIds: ['chengdu', 'chongqing', 'guiyang', 'kunming', 'lhasa'],
|
||||
},
|
||||
{
|
||||
id: 'northwest',
|
||||
name: '西北',
|
||||
nameEn: 'Northwest',
|
||||
sortOrder: 7,
|
||||
themeColor: '#F4D03F',
|
||||
cityIds: ['xian', 'lanzhou', 'xining', 'yinchuan', 'urumqi'],
|
||||
},
|
||||
{
|
||||
id: 'hk_macao',
|
||||
name: '港澳',
|
||||
nameEn: 'HK & Macao',
|
||||
sortOrder: 8,
|
||||
themeColor: '#E74C3C',
|
||||
cityIds: ['hongkong', 'macao'],
|
||||
},
|
||||
]
|
||||
|
||||
// 分页:1 页(8 项 ≤ 9)
|
||||
export const chinaRegionPages = [chinaRegions]
|
||||
|
||||
export default chinaRegions
|
||||
70
js/content/shared/level-presets.js
Normal file
70
js/content/shared/level-presets.js
Normal file
@@ -0,0 +1,70 @@
|
||||
export function createLevelPresets(seedBase) {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
difficultyTier: 'intro',
|
||||
seedBase: seedBase + 1,
|
||||
elementCount: 6,
|
||||
piecesPerElement: 3,
|
||||
layers: 2,
|
||||
density: 'low',
|
||||
targetPassRate: 0.95,
|
||||
targetDurationSec: [90, 150],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
difficultyTier: 'warmup',
|
||||
seedBase: seedBase + 2,
|
||||
elementCount: 7,
|
||||
piecesPerElement: 3,
|
||||
layers: 2,
|
||||
density: 'low',
|
||||
targetPassRate: 0.9,
|
||||
targetDurationSec: [100, 160],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
difficultyTier: 'ramp',
|
||||
seedBase: seedBase + 3,
|
||||
elementCount: 8,
|
||||
piecesPerElement: 3,
|
||||
layers: 3,
|
||||
density: 'medium',
|
||||
targetPassRate: 0.8,
|
||||
targetDurationSec: [120, 180],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
difficultyTier: 'mid',
|
||||
seedBase: seedBase + 4,
|
||||
elementCount: 9,
|
||||
piecesPerElement: 3,
|
||||
layers: 3,
|
||||
density: 'medium',
|
||||
targetPassRate: 0.7,
|
||||
targetDurationSec: [130, 190],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
difficultyTier: 'hard',
|
||||
seedBase: seedBase + 5,
|
||||
elementCount: 10,
|
||||
piecesPerElement: 3,
|
||||
layers: 4,
|
||||
density: 'medium_high',
|
||||
targetPassRate: 0.6,
|
||||
targetDurationSec: [150, 220],
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
difficultyTier: 'boss',
|
||||
seedBase: seedBase + 6,
|
||||
elementCount: 10,
|
||||
piecesPerElement: [3, 3, 3, 3, 3, 6, 3, 3, 3, 3],
|
||||
layers: 4,
|
||||
density: 'high',
|
||||
targetPassRate: 0.55,
|
||||
targetDurationSec: [180, 260],
|
||||
},
|
||||
]
|
||||
}
|
||||
14
js/content/shared/pagination.js
Normal file
14
js/content/shared/pagination.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// 通用分页工具 — 将数组按 pageSize 分页
|
||||
// 默认 pageSize = 9(3x3 棋盘)
|
||||
|
||||
export function paginate(items, pageSize = 9) {
|
||||
const pages = []
|
||||
for (let i = 0; i < items.length; i += pageSize) {
|
||||
pages.push(items.slice(i, i + pageSize))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
export function getPageCount(totalItems, pageSize = 9) {
|
||||
return Math.ceil(totalItems / pageSize)
|
||||
}
|
||||
Reference in New Issue
Block a user