开始菜单、玩家选择、脸部绘制
This commit is contained in:
@@ -121,3 +121,77 @@ SubViewportContainer`,输入天然可达** —— 不是把 SubViewport 当后
|
||||
**发现**:`Net` autoload 的「联机测试」面板默认可见且在同位置,会把菜单中间的按钮盖住 ——
|
||||
接线时必须先处理它(隐藏,或让菜单的「联机」按钮接管)。这条已记进 MEMORY.md。
|
||||
|
||||
## 实现:角色选择 + 脸部预设选择 + 脸部绘制
|
||||
|
||||
按之前的方案落地了。`test_run` **26/26 通过**(含新增的 face suite 5 条),实机跑通并截图确认。
|
||||
|
||||
**新增**
|
||||
- `character/player/face/face_paint.gdshader` — 孤岛 UV 重映射 + `mix(base, paint, paint.a)`
|
||||
- `character/player/face/face_painter.gd` — 笔画层,直接改 RGBA8 字节缓冲
|
||||
- `character/player/face/face_rig.gd` — 挂 surface 1 的材质、切预设、存读档(`user://face_*.json/png`)
|
||||
- `character/player/face/presets/face_01.png` `face_02.png` — 从 `mouse_表情测试.png` 裁的 512² 方形预设
|
||||
- `ui/paint_panel.tscn/.gd` — 绘画面板(颜色 / 粗细 / 橡皮 / 清空 / 取消 / 完成)
|
||||
- `ui/character_select.tscn/.gd` — 3D 预览(自转)+ 预设缩略图 + 自己画
|
||||
- `tests/test_face.gd` — 钉住「surface 1 叫 face、UV 孤岛落在 shader 的框里、预设是正方形」
|
||||
|
||||
**改动**:`player.tscn` 加 `FaceRig` 节点;`main_menu.gd`「开始游戏」→ 角色选择,并把 Net 调试面板收起来。
|
||||
|
||||
**踩到的坑(都补进 MEMORY.md 了)**
|
||||
1. Godot 4 的 canvas **没有擦除混合模式**,`draw_set_blend_mode` 也没了 → 橡皮改成自己乘 alpha。
|
||||
2. `Image.set_data()` 在 4.7 变成 5 个参数 → 改用 `Image.create_from_data`。
|
||||
3. 导出的**节点引用**在场景实例化时解析成 null → 改成 `mesh_path: NodePath` + `_ready()` 里 `get_node_or_null`。
|
||||
4. shader 里 `vec2` 不能用 `source_color`(只给 vec3/vec4/sampler)。
|
||||
5. 画布一开始只显示笔画层,等于让玩家对着空气画 → 底下垫一层预设 TextureRect。
|
||||
6. 拖拽判定原本看 motion 的 `button_mask`,MCP 注入的 motion 不带这个字段 → 改成自己记 `_drawing`。
|
||||
7. 排查时一度以为画笔没生效,其实黑点画在脸的黑色线条上被淹没了 —— 换到纯蓝区域才看见。
|
||||
诊断顺序记一下:先 `print` 确认输入到了(`[PP]`)→ 再确认印章落了(`[FP] stamp`)→ 再看缓冲字节(`probe a=255`)。
|
||||
|
||||
## 收尾:入口换成开始菜单 + 联机脸同步
|
||||
|
||||
`test_run` **28/28 通过**。两件事都用实机验证过(入口流程用 MCP 点按钮走通;脸同步用**两个
|
||||
headless 实例** `--host` / `--join 127.0.0.1` 真连了一次)。
|
||||
|
||||
**入口场景**
|
||||
- `project.godot` 的 `run/main_scene` 改成 `res://ui/main_menu.tscn`(用 `project_manage(set_main_scene)` 改的)。
|
||||
- `net.gd`:加 `WORLD_SCENE` / `MENU_SCENE`、`_enter_world()`、`_go_to()`、`set_menu_visible()`;
|
||||
`host_game()` 和 `_on_connected_to_server()` 之后切进世界;`leave_game()` 切回菜单并把 `_spawner` 置空。
|
||||
- **关键**:世界是开局后才加载的,`bind_spawner()` 必须补生成已经连上的玩家,否则主机在菜单里
|
||||
开好服、进世界时没有角色。
|
||||
- `main_menu.gd`:「确定」→ `Net.host_game()`;用 `Net.set_menu_visible()` 代替原来的节点路径 hack。
|
||||
- 新增测试 `test_main_scene_is_the_menu`(防有人把入口改回世界)。
|
||||
|
||||
**脸同步**
|
||||
- `FaceRig` 加三个方法:`_pull_remote_face` / `_rpc_request_face` / `_rpc_send_face`。
|
||||
**用「谁缺谁来要」而不是出生时推** —— 各端玩家节点出现的先后顺序不保证,推的话很可能推给一个
|
||||
还不存在的节点。非本机玩家在 `_ready` 里主动去要,带重试。
|
||||
- `FacePainter` 加 `to_png_bytes()` / `set_image()`,走内存不落盘。
|
||||
- **踩到的坑**:第一次跑双实例,客户端刷了一屏
|
||||
`Node not found: "Main/<id>/FaceRig"` / `Failed to get path from RPC` ——
|
||||
主机生成玩家比客户端早几帧,主机立刻去要时客户端还没建出那个节点。
|
||||
加 `FACE_SYNC_INITIAL_DELAY = 1.0`(首次要之前先等一秒)后两边都干净了。
|
||||
- 验证结果:HOST 和 JOIN 都打出「收到 peer X 的脸,png=1930 字节」,且无任何报错。
|
||||
1930 正好是 `user://face_paint.png` 的大小,说明笔画真的传过去了。
|
||||
- 新增测试 `test_face_sync_methods_exist`(钉住三个方法名)。
|
||||
|
||||
**找到 Godot 可执行文件**:`D:\_yvmou\Godot\Godot_v4.7.2-stable_win64.exe\Godot_v4.7.2-stable_win64_console.exe`
|
||||
(注意那一串带 .exe 的其实是个**目录**)。双开调试命令:
|
||||
`<godot> --headless --path E:/Godot/agame -- --host` / `-- --join 127.0.0.1`。
|
||||
|
||||
## 修 bug:点「自己画」不是空白画布
|
||||
|
||||
用户报的。根因是**语义理解错了**:我原先把「自己画」做成「在选中的预设上补几笔」,
|
||||
用户要的是**从空白脸起手**。
|
||||
|
||||
- 生成 `presets/face_00_blank.png`(512² 纯色 `#89B3FF`,取自预设贴图里脸的底色)。
|
||||
- `character_select.gd`:「自己画」= 清掉缩略图高亮 + `_paint_panel.open(_rig, BLANK_FACE)`。
|
||||
- `paint_panel.gd`:`open()` 多一个 `blank_face` 参数,**先拍快照再换底图 + 清笔画**。
|
||||
- **顺带修了一个连带 bug**:`_on_cancel` 原来只还原笔画,而「自己画」会把底图换成空白 ——
|
||||
点取消会留下一张白脸。现在底图(`_preset_before`)也一起还原。
|
||||
- 移掉了 `_on_paint_done`(高亮在 `_on_draw` 里已经清了,那个回调成了死代码)。
|
||||
|
||||
验证:实机走了一遍「选预设 → 自己画(画布变纯色、预览里脸也变纯)→ 取消(底图还原回 face_01)」,
|
||||
并用 `get_node_info` 确认两个缩略图 modulate 都回到 0.62。`test_run` 28/28。
|
||||
|
||||
**一个排查小教训**:截图里 Preset0 看着比 Preset1 亮,我一度以为高亮没清掉 ——
|
||||
其实两张贴图本身明暗就不同,`modulate` 才是真相。**别靠截图判断颜色,去读属性。**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user