Honey Village: six model builds + hub frontend, Dockerized for Dokploy
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# CONTRACT.md — 资产 / 地图 / 代码三方契约(唯一真源)
|
||||
|
||||
工作目录:`/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3`
|
||||
PRD:同目录 `PRD.md`(所有剧情/数值/台词以 PRD 为准,本文件只定义技术接口)。
|
||||
|
||||
工具路径:
|
||||
- Aseprite: `/Applications/Aseprite.app/Contents/MacOS/aseprite`(用法:`aseprite -b --script file.lua`;绘制用 `app.activeImage:drawPixel(x, y, app.pixelColor.rgba(r,g,b,a))`;导出用 `spr:saveAs("out.png")`。已验证可用)
|
||||
- Tiled 1.12.2: `/Applications/Tiled.app/Contents/MacOS/Tiled`(用法:`Tiled -e script.js` 执行脚本,脚本内用 `var f = new TextFile(path, TextFile.WriteOnly); f.write(xml); f.commit();` 写 .tmx;再用 `Tiled --export-map --embed-tilesets in.tmx out.json` 导出 JSON。已验证可用;注意 `-e` 模式无编辑器,`tiled.open`/`TileMap` 部分 API 不可用,一律走 TextFile 写 XML)
|
||||
|
||||
## 1. 目录结构
|
||||
|
||||
```
|
||||
public/assets/
|
||||
tileset.png # 256×128,16×16 瓦片,16 列 × 8 行 = 128 瓦片
|
||||
sprites/player.png # 64×96:帧 16×24,4 列(行走帧 0-3) × 4 行(方向 0=down 1=up 2=left 3=right),第 0 帧兼待机
|
||||
sprites/npc_afu.png # 48×24:3 帧横排 = smile / flat / off
|
||||
sprites/npc_yuanyuan.png # 同上
|
||||
sprites/npc_dabao.png # 同上
|
||||
sprites/npc_mimi.png # 同上
|
||||
sprites/npc_fuyisheng.png # 同上
|
||||
sprites/npc_guiyeye.png # 同上
|
||||
sprites/npc_bird.png # 32×24:2 帧 = 闭嘴 / 张嘴
|
||||
sprites/extra_squirrel.png # 32×24:2 帧循环
|
||||
sprites/extra_hedgehog.png # 同上
|
||||
sprites/extra_fox.png # 同上
|
||||
sprites/extra_pig.png # 同上
|
||||
sprites/extra_chick.png # 同上
|
||||
portraits/player_smile.png # 32×32
|
||||
portraits/player_real.png # 32×32(E3 用:微笑消失、疲惫真实的脸)
|
||||
portraits/afu.png yuanyuan.png dabao.png mimi.png fuyisheng.png guiyeye.png bird.png # 各 32×32,smile
|
||||
maps/house.json plaza.json bakery.json shop.json clinic.json lake.json field.json well.json fog.json white.json
|
||||
maps/*.tmx # Tiled 中间产物(保留在仓库)
|
||||
maps/tileset.tsx # 外部瓦片集描述,image source="../tileset.png"
|
||||
tools/aseprite/*.lua # 素材生成脚本(保留)
|
||||
tools/tiled/genmaps.js # 地图生成脚本(保留)
|
||||
src/ # 游戏代码
|
||||
```
|
||||
|
||||
素材规范(PRD §11):糖果色板(草绿 #7DC95E/#5FB34A、奶油黄 #FFF3D6、蜜糖橙 #F5A623、天空蓝 #8FD3FF、石路 #E8DCC8、湖水 #6EC1E4/#4FA8D8、粉 #F7B7CB、棕 #8B5A2B),白色层独立灰白板(#F5F5F5/#DADADA/#BDBDBD)。无抗锯齿、无渐变。`off` 档与 `smile` 档差异控制在 1–2 像素(如一只眼低 1px 或嘴角多 1px),不许鬼脸。背景透明(alpha=0)。PNG 必须精确尺寸(上面列出)。
|
||||
|
||||
## 2. 瓦片 ID 表(tileset.png,id = 行×16+列;地图数据 gid = id+1)
|
||||
|
||||
| id | 名称 | id | 名称 |
|
||||
|---|---|---|---|
|
||||
| 0 草地 | 1 草+花A | 2 草+花B | 3 深草 |
|
||||
| 4 土路 | 5 石路 | 6 石路alt | 7 广场砖 |
|
||||
| 8 湖水A | 9 湖水B | 10 水岸北 | 11 水岸南 |
|
||||
| 12 水岸西 | 13 水岸东 | 14 花坛粉 | 15 花坛黄 |
|
||||
| 16 莓果丛(满) | 17 莓果丛(空) | 18 树左上 | 19 树右上 |
|
||||
| 20 树左下 | 21 树右下 | 22 圆灌木 | 23 树桩 |
|
||||
| 24 石头 | 25 路标 | 26 栅栏横 | 27 栅栏竖 |
|
||||
| 28 路灯 | 29 彩带红 | 30 彩带黄 | 31 彩带蓝 |
|
||||
| 32 奶油墙 | 33 奶油墙+窗 | 34 木板墙 | 35 橙屋顶左 |
|
||||
| 36 橙屋顶中 | 37 橙屋顶右 | 38 门 | 39 门框顶 |
|
||||
| 40 窗 | 41 烟囱 | 42 井左上 | 43 井右上 |
|
||||
| 44 井左下 | 45 井右下 | 46 邮筒 | 47 公告板 |
|
||||
| 48 木地板A | 49 木地板B | 50 室内墙 | 51 室内墙+窗 |
|
||||
| 52 床左上 | 53 床右上 | 54 床左下 | 55 床右下 |
|
||||
| 56 柜台左 | 57 柜台右 | 58 烤炉 | 59 空货架 |
|
||||
| 60 满货架 | 61 桌子 | 62 椅子 | 63 地毯 |
|
||||
| 64 日历 | 65 配方纸 | 66 文件纸 | 67 野餐布左上 |
|
||||
| 68 野餐布右上 | 69 野餐布左下 | 70 野餐布右下 | 71 长椅左 |
|
||||
| 72 长椅右 | 73 凳子 | 74 柜子 | 75 冰箱 |
|
||||
| 76 水槽 | 77 盆栽 | 78 木桶 | 79 木箱 |
|
||||
| 80 雾A | 81 雾B | 82 雾C | 83 白色地板 |
|
||||
| 84 白色墙 | 85 白墙板 | 86 白门 | 87 白床左上 |
|
||||
| 88 白床右上 | 89 白床左下 | 90 白床右下 | 91 白柜 |
|
||||
| 92 白监护仪 | 93 白窗帘 | 94 白地板alt | 95 白天花灯 |
|
||||
| 96 梯子 | 97 桥横 | 98 桥竖 | 99 蘑菇 |
|
||||
| 100 花红 | 101 花黄 | 102 花蓝 | 103 蜂蜜罐 |
|
||||
| 104 面包 | 105 信件 | 106 书 | 107 蜡烛 |
|
||||
| 108 篮子 | 109 水桶 | 110 扫帚 | 111 蛋糕 |
|
||||
| 112 红屋顶左 | 113 红屋顶中 | 114 红屋顶右 | 115 蓝屋顶左 |
|
||||
| 116 蓝屋顶中 | 117 蓝屋顶右 | 118 粉墙 | 119 粉墙+窗 |
|
||||
| 120 石墙 | 121 石墙+窗 | 122 遮阳篷 | 123 钟 |
|
||||
| 124 旗 | 125 花环角 | 126 花环中 | 127 空(透明) |
|
||||
|
||||
## 3. 地图契约(Tiled 导出 JSON;图层固定三层)
|
||||
|
||||
每层地图固定:
|
||||
- `ground`(瓦片层,无碰撞;必须全部用不透明瓦片——透明装饰瓦片只能放 `obstacles` 层,否则透明处露出黑底。大花 100-102、蘑菇 99、门 38 已在 tileset 里烘焙不透明底,可放 ground)
|
||||
- `obstacles`(瓦片层,带图层自定义属性 `collides=true`(bool);代码对该层整层碰撞,但彩带(瓦片 29-31)在代码里排除碰撞、可穿过)
|
||||
- `objects`(对象层,点对象)
|
||||
|
||||
对象约定(name + 自定义属性):
|
||||
- `name="spawn"`,属性 `id`(string):出生点。各图必有 `default`;室内图另有 `from_plaza`;plaza 有 `from_house/from_bakery/from_shop/from_clinic/from_lake/from_field/from_well/from_fog`。
|
||||
- `name="door"`,属性 `target`(string, 目标地图 key) + `spawn`(string, 目标 spawn id)。双向成对。
|
||||
- 落点安全:spawn 与任一门判定点的距离(以玩家测量点 y-8 计)必须 >14px(惯例 ≥24px);运行时另有门武装机制兜底——落到门旁时须先离开感应圈(>18px)才允许触发,且触发即消耗武装(须再次离开 >18px 才可重新触发),防止落点回弹与对话关闭帧的重复触发。
|
||||
- 2x2 拼块瓦片(树 18-21、井 42-45、床 52-55、野餐布 67-70、白床 87-90):四个象限占用连续 4 个 id;tileset 生成时把下半两个象限从自然落点(id+16/id+17)复制到 id+2/id+3。
|
||||
- `name="npc"`,属性 `id`(string):afu / yuanyuan / dabao / mimi / fuyisheng / guiyeye / bird / squirrel / hedgehog / fox / pig / chick。
|
||||
- `name="interact"`,属性 `id`(string):见下表。
|
||||
|
||||
10 张地图(尺寸 = 瓦片数;场景 key 同文件名):
|
||||
|
||||
| key | 文件 | 尺寸 | 必填对象 |
|
||||
|---|---|---|---|
|
||||
| house | maps/house.json | 12×8 | spawn(default,from_plaza)、door→plaza、interact:bed、interact:calendar |
|
||||
| plaza | maps/plaza.json | 30×20 | spawn(default,from_house,from_bakery,from_shop,from_clinic,from_lake,from_field,from_well,from_fog)、door×8(house/bakery/shop/clinic/lake/field/well/fog)、npc:afu(公告板旁)、npc:bird(树上)、npc:squirrel、npc:fox、interact:noticeboard、interact:flowerbed_1/2/3 |
|
||||
| bakery | maps/bakery.json | 15×10 | spawn(default,from_plaza)、door→plaza、npc:yuanyuan、interact:counter_bread、interact:recipe_paper |
|
||||
| shop | maps/shop.json | 15×10 | spawn(default,from_plaza)、door→plaza、npc:mimi、npc:hedgehog、interact:shelf_count |
|
||||
| clinic | maps/clinic.json | 12×8 | spawn(default,from_plaza)、door→plaza、npc:fuyisheng、interact:doctor_desk |
|
||||
| lake | maps/lake.json | 24×16 | spawn(default,from_plaza)、door→plaza、npc:guiyeye(长椅旁)、npc:pig、interact:picnic_mat |
|
||||
| field | maps/field.json | 20×14 | spawn(default,from_plaza)、door→plaza、npc:chick、interact:berry_1..5、interact:water_point |
|
||||
| well | maps/well.json | 14×10 | spawn(default,from_plaza)、door→plaza、interact:ancient_well |
|
||||
| fog | maps/fog.json | 20×8 | spawn(default,from_plaza)、door→plaza、interact:fog_wall |
|
||||
| white | maps/white.json | 20×14 | spawn(default);上半 20×6 走廊 + 左下 10×8 病房,内部连通;白色层瓦片(83–95) |
|
||||
|
||||
地图要点(PRD §10):plaza 为枢纽,含公告板(47)、花坛(14/15)、双子鸟树(18-21)、庆典空地;室外场景用草地/石路/栅栏/房屋装饰铺满,lake 有大片湖水(8-13)与长椅(71/72),field 有莓果丛(16),well 有古井(42-45),fog 边缘铺雾(80-82),white 全用白色层瓦片(走廊+病房,病房内放白床 87-90 与白监护仪 92)。室内场景:墙(50/51)围边、木地板(48/49)、家具按 PRD §10 要点摆放。house 必须有床(52-55)与日历(64);bakery 有柜台(56/57)、烤炉(58)、配方纸(65);shop 有货架(59/60);clinic 有桌子(61)+文件纸(66)。
|
||||
|
||||
## 4. 代码架构契约(Phaser 3 + TS + Vite)
|
||||
|
||||
- `src/main.ts`:Phaser config,逻辑 320×180,`pixelArt:true`,`scale:{ mode: Phaser.Scale.NONE, autoCenter: CENTER_BOTH, parent:'game' }` + window resize 监听做整数倍放大(canvas style 宽高 = 320k×180k,k = max(1, floor(min(winW/320, winH/180))))。
|
||||
- 场景 key:`BootScene / TitleScene / HouseScene / PlazaScene / BakeryScene / ShopScene / ClinicScene / LakeScene / FieldScene / WellScene / FogScene / WhiteScene / UIScene / DreamScene / EndingScene`。
|
||||
- 地图场景共用基类 `MapScene`(`src/scenes/MapScene.ts`):子类只提供 `mapKey` 与少量钩子。基类负责:tilemap 加载(`this.load.tilemapTiledJSON`,tileset 名 `candy` 对应 `assets/tileset.png`)、player(96 px/s、四向动画 walk-down/up/left/right + 待机帧、obstacles 层碰撞、相机跟随+钳制)、≤24px 出「按 E」提示(交 UIScene 显示)、door 切换(fade out/in + 目标 spawn)、NPC/群演实例化与表情档切换、注册 CorruptionDirector 的视听参数(相机 postFX:ColorMatrix 饱和度 / Vignette 晕影 / 负片单帧)。
|
||||
- `CorruptionDirector`(`src/core/CorruptionDirector.ts`):普通 TS 单例 + `Phaser.Events.EventEmitter`。状态:playerName、startTime(ms)、day(1-7)、happiness(0-100)、awareness(0-100)、clues(Set)、tasksDone(Set)、refusedTasks(Set)、escapedCelebrations、stage 派生值。事件名:`happiness` `awareness` `stage` `day` `clue` `task` `celebration` `ending`。是全部状态唯一真源;提供 debug 用 setter。
|
||||
- 对话:`UIScene` 底部通栏框(说话者名 + 头像 + 文本,E 推进;选项三选:温柔/迟疑/否定);文本腐蚀在渲染层按 §6.5 表替换(原文案干净)。头像用 portraits/。
|
||||
- 音频:`src/audio/AudioEngine.ts`,WebAudio 程序合成(无音频文件)。
|
||||
- Debug:`src/debug/DebugPanel.ts`,反引号键开关的 DOM 面板(默认隐藏、无 UI 痕迹):设幸福/觉知/日(1-7)/传送场景/置齐线索/强制结局 E1-E4。
|
||||
- 数值与台词逐字逐数实现 PRD §5–§9。
|
||||
|
||||
## 5. 验收相关硬约束
|
||||
|
||||
- `npm run build`(tsc --noEmit + vite build)必须零错误;`npm run preview` 可玩。
|
||||
- 无 localStorage、无外部网络请求、无外部音频/字体文件。
|
||||
- 控制台零报错。
|
||||
Reference in New Issue
Block a user