5.0 KiB
agame 项目长期笔记
Godot 4.7.2(Forward+,Jolt Physics,D3D12)。编辑器位于
D:\_yvmou\Godot\Godot_v4.7.2-stable_win64.exe\Godot_v4.7.2-stable_win64.exe(另有 mono 版)。
代码约定
- GDScript 警告被当作错误(至少
inference_on_variant)。不要写成var x := some_variant_returning_call();要显式写类型,例如var s: Script = node.get_script() as Script。改完脚本务必用--check-only --script res://xxx.gd自查。 - 缩进用 tab,注释用中文(项目既有风格)。
无头验证的正确姿势(踩过坑)
--check-only --script res://x.gd:GDScript 语法校验,有效。godot --headless --editor --path <proj> --quit:验证编辑器插件能否加载,有效。- 不要用
extends SceneTree的--script脚本去测_ready()相关行为: 这种模式下节点不会真正进入场景树(is_inside_tree()为 false),_ready不执行, 会得出完全错误的结论。正确做法是造一个临时场景,用位置参数当主场景跑:godot --headless --path <proj> res://tools/_tmp_probe.tscn。 - 即使是
--headless(dummy 渲染后端),shader 编译错误仍会被报告 (SHADER ERROR: ...),所以可以用无头运行来校验 shader 语法。
玩家 = LimboAI LimboHSM(2026-10-15 起)
- LimboAI v1.8.1 是 GDExtension 版(addons/limboai 只有 bin/,无 plugin.cfg),
不需要启用 editor plugin;ClassDB 里没有 HSMPlayer ——
LimboHSM/LimboState本身就是 Node。 - 玩家状态机在
character/player/hsm/:根player_hsm.gd(Grounded⇄Airborne)+ Grounded{Idle,Walk,Sprint,Crouch,Sneak} + Airborne{Jump,Fall},全是场景节点、脚本挂状态上。 - 分工:HSM 管「是什么状态」(写 motor.target_speed/crouching/sprinting + 调
animator.play_state),motor 只管物理(重力/加速度/跳跃缓冲 + try_jump),
animator 只管「怎么播」(play_state + set_gait 刷倍率)。player.gd 管线第一位
hsm.update(delta)(MANUAL 模式,仅权威端 initialize+set_active;远端靠 Sync 复制)。 - 走/站立转换按输入判定(非旧版的速度阈值)——顶墙时播 walk 不播 idle,是预期行为。
- 用法要点:子机
_enter里可set_initial_state()动态挑入口子状态;环境判定 (起跳/踏空/落地)放叶子状态的 _update,别放父机;落地判定要带vy<=0门槛。 - 踩坑:新 class_name 后无头
--check-only报「Could not find type」= 全局类缓存没刷新, 让编辑器 scan 一次即解;MCP node_set_property 写 enum int 失败 → 手改 tscn + 场景 force_reload。
toon 卡通渲染管线
shader/cel-shader-base.gdshader(USE_*宏开关各模块)+shader/includes/*.gdshaderinc, 上游是 godot4-cel-shader 项目。shader/toon.tres是材质模板;shader/outline.gdshader作为next_pass描边。shader/toon_apply.gd(@tool Node3D)给每个 MeshInstance3D 复制一份独立材质, 因为每个模型有各自的贴图,所以必须独立(不能共享一份材质)。- 已在项目设置里用了 global uniform:
diffuse_curve、specular_smoothness、fresnel_smoothness、outline_width、outline_color—— 这几项调参本来就是全局实时生效。 - 贴图尺寸极不统一(289 张 PNG / 24 种尺寸,1024²、512²、4096²、32² 混杂), 因此不适合 Texture2DArray + per-instance uniform 方案(显存会爆且要额外打包流水线)。
- 编辑器插件
addons/toon_refresh/:改 toon.tres 时自动重刷 toon_apply 材质。
坐标系陷阱 + 上游着色器的边界(重要)
Godot 4 的 fragment() 里 NORMAL / TANGENT / BINORMAL 都处于视图空间,
而 NORMAL_MAP 要的是切线空间值、由引擎用 TANGENT/BINORMAL 还原。
把切线空间值直接赋给 NORMAL 会让整个场景的法线变成一个跟着相机转的常量 ——
表现为平视全黑、俯瞰才亮。
但不要因此去改上游文件:cel-shader-base.gdshader 与
includes/normal-map.gdshaderinc 来自 https://github.com/eldskald/godot4-cel-shader,
本项目的策略是逐字跟随上游。上游的法线贴图路径 NORMAL = normal.vector;
确实有上述坐标空间错误,但上游所有变体都是 #define USE_NORMAL_MAP 0,
全仓库从未启用过这条路径(README 也没提),所以是"能编译但结果错"的死代码。
本项目保持 USE_NORMAL_MAP 0,与上游一致;toon.tres 里残留的
shader_parameter/normal_scale 在宏关闭时会被忽略,无副作用。
结论:要动上游 shader 之前,先用 E:/Godot/godot4-cel-shader-main/ 里的干净副本 diff。
正确做法(若将来真要开法线贴图):只写 NORMAL_MAP = 原始切线空间值 +
NORMAL_MAP_DEPTH,让引擎合成;不要自己写 NORMAL,也不要预先做 *2-1 重映射
(引擎自己做,蓝通道由引擎重建)。