开始菜单、玩家选择、脸部绘制

This commit is contained in:
2026-10-02 12:06:28 +08:00
parent fbf00cf11f
commit 698cb02c21
26 changed files with 1419 additions and 21 deletions
+37 -2
View File
@@ -11,8 +11,15 @@
- 界面放 `res://ui/`。项目没有 Theme 资源,风格一律用节点上的 `theme_override_*` 内联写;
给容器(如 VBoxContainer)设 `theme_override_styles/*` 会**向下继承**给子按钮,不用逐个设。
- 中文字体不用额外配:Godot 默认主题会回退到系统字体,实测中文正常渲染。
- **`Net` 是 autoload,它的「联机测试」面板在 `_ready()` 里就 `visible = true`(CanvasLayer layer=20)**,
会盖在任何场景正中间。做开始菜单时要么让菜单的「联机」按钮接管它,要么在菜单期间把它藏起来。
- **入口场景是 `res://ui/main_menu.tscn`**(不再是世界)。流程:开始菜单 →「开始游戏」→ 角色选择 →
「确定」= `Net.host_game()` → Net 切到 `world/main.tscn`;「联机」= 放出 Net 的创建/加入面板,
选完同样由 Net 切进世界。**进世界 / 回菜单这两件事都归 Net 管**(`_enter_world` / `leave_game`),
菜单只管「按了哪个按钮」。
- **世界是开局之后才加载的**,所以 `MultiplayerSpawner` 的绑定时机跟着变了:
`Net.bind_spawner()` 里要把已经连上的玩家补生成一遍,否则主机在菜单里就开好服、
切进世界时一个角色都不会出现。
- `Net` 是 autoload,它的「联机测试」面板在 `_ready()` 里就 `visible = true`(CanvasLayer layer=20),
会盖在菜单正中间 —— 菜单调 `Net.set_menu_visible(false)` 收起来。
## 动画(AnimationPlayer)
@@ -40,6 +47,34 @@
- 面部孤岛只占 1024² 的 21%×20%,实际脸分辨率约 219×205 —— 要用 shader 把孤岛重映射到 0~1
再用方形小贴图,有效分辨率能翻一倍多。
## 面部系统(character/player/face/ + ui/)
- `face_paint.gdshader`:把孤岛 UV 重映射到 0~1,`ALBEDO = mix(base_tex, paint_tex, paint.a)`。
**两层必须分开**:`base_tex` = 预设脸(切换就换它),`paint_tex` = 玩家笔画层。
这样橡皮擦掉笔画露出来的是预设脸,而且换预设不会丢手绘。
- `FaceRig`(挂在 Player 下):建一张 512² 的笔画 Image + ImageTexture,`set_surface_override_material(1, mat)`。
存 `user://face_preset.json`(选了哪张预设)+ `user://face_paint.png`(透明底笔画层),
玩家出生时 `apply_saved()` 读回来。预览和玩家是**两套 FaceRig、共用一份存档**。
- `FacePainter`:**不用 `Control._draw()`,直接改 RGBA8 字节缓冲**。画 = source-over alpha 混合,
擦 = 把目标 alpha 乘掉;一笔画完 `_sync()` 一次(512² 一次 1MB,别每盖一个印章就同步)。
- 界面链路:`ui/main_menu.tscn` →「开始游戏」→ `ui/character_select.tscn`(3D 预览 + 预设缩略图 + 自己画)
→ `ui/paint_panel.tscn`。**画布要「预设 TextureRect + 笔画 TextureRect」叠着显示** ——
笔画层是透明底的,只显示它等于让玩家对着空气画。
- **「自己画」= 从空白脸起手**(`presets/face_00_blank.png`,纯色底),不是在预设上补笔。
空白由面板来落(`open(rig, blank_face)`)—— 它必须**先拍快照再改**,否则点「取消」还原回来的
是已经清空的状态。取消要同时还原**底图和笔画**,只还原笔画会留下一张白脸。
## Godot 4 踩坑
- **canvas 没有「擦除」混合模式**:`CanvasItemMaterial.BlendMode` 只有 mix/add/sub/mul/premult,
`CanvasItem.draw_set_blend_mode()` 在 4.x 已移除。橡皮只能自己管像素。
- `Image.set_data()` 在 4.7 签名变了(要 5 个参数);改用
`Image.create_from_data(w, h, mipmaps, format, data)`。
- **导出的节点引用解析不到**:`@export var mesh: MeshInstance3D` 在 .tscn 里存成 `NodePath`,
实测场景实例化时拿到的是 null。改成 `@export var mesh_path: NodePath` + `_ready()` 里 `get_node_or_null`。
- shader 里 `source_color` 只能用在 vec3 / vec4 / sampler 上,`vec2` 用了会编译失败。
- 给容器(VBoxContainer 等)设 `theme_override_styles/*` 会**向下继承**给子按钮,不用逐个设。
## Godot MCP 踩坑
- **数值标量经 MCP 会被字符串化**:`node_set_property` 传 `0.15` 能写进去,但回显是 `"0.15"`;