内容
约定:
通用按钮:新游戏(New Game/Play/Start)、重开(Restart)、继续玩(Continue)、暂停(Pause)、恢复(Resume)、退出(Quit/Exit)、设置(Options/Settings)。
Save/Load(存档/加载)、呼出菜单(Esc/Escape、通常会暂停游戏)
节点命名模板
特殊:
游戏资源对象默认全局共享,但可通过“唯一化”或duplicate()方法创建个副本,以免一处修改就影响全部引用处。
线程异常(属性set中调)可用 _Callable.CallDeferred() 或 _Node3D.CallDeferredThreadGroup("die"); 解决。
change_scene_to_packed 载入大场景时会闪出默认灰色背景,色调改一致可临时缓解 RenderingServer.set_default_clear_color(color);或彻底解决:
截图老场景盖住节点树,等新场景异步载入后再撤掉;截图 get_tree().get_root().get_texture().get_image()。
死记:
节点区别 - RigidBody3D PhysicsMaterial Bounce = 1 则为完全反弹,而 CharacterBody3D 则要手动处理碰撞。
如果 override 了自定义节点的 _Ready(),则必须先调一下 base._Ready(),重写内置节点则不用。
AnimationTree的active为true时,其anim_player指定的AnimationPlayer.Play(...)的调用会失效。
有时模型动画并非原地动画(In-place Animation),为了避免动画跳起越框问题,故可采用固定根骨骼的根运动(AnimationTree root_motion_track/UE5叫EnableRootMotion)方式,同步动画与碰撞体的位移,等同固定了动画中心点,也可在 _PhysicsProcess(delta) 首行修正方向:
if (at.RootMotionTrack != null)
{
var rm = new Transform3D(new Basis(at.GetRootMotionRotation()), at.GetRootMotionPosition());
sk.Transform = rm;
}
Player 整体节点由 MoveAndSlide() 控制,不能为了迁就其模型子节点(Node3D.Rotation等)而改动:
var n = ((Node3D)player.GetNode("模型节点/不含碰撞体"));
// 根骨骼指定后,方向可通过 direction.X、direction.Z 加 ± 调整。
var y = Mathf.LerpAngle(n.Rotation.Y, Mathf.Atan2(direction.X, direction.Z), delta * Speed);
n.Rotation = new Vector3(n.Rotation.X, (float)y, n.Rotation.Z); // 根据玩家输入方向来控制模型朝向(东西南北)。
2D项目不需要Camera2D摄像头节点,3D项目则需要Camera3D+环境节点;2.5D俯视角游戏通常采用45%角度。
TouchScreenButton - 因触摸设备横行,故用其换掉不支持多点触控的Button节点;
默认无尺寸不显示,必须拖拽个图片(icon.svg)或新建个GradientTexture2D至texture_normal;
在PC上 GetNode("TouchScreenButton").Pressed += () => GD.Print("Hi!") 启用“项目设置->输入设备->指点->用鼠标模拟触摸”后才会触发。
协作:
控制方向 - Node3D.Rotation 是 Vector3 类型,X 轴管横向左右⇄,Y 轴管竖向高低⇅,Z 轴管前后远近⤢。
CharacterBody3D WASD 控制:
var velocity = Velocity; // 直接修改结构体,就无法进行原始值参与的计算了;初始值为(0, 0)。
// 施加重力: velocity += GetGravity() * (float)delta; // 或直接用 new Vector3(0, -9.8, 0);
Velocity = velocity; // 该结构体只是暂存当前帧变动偏移值,还得通过 MoveAndSlide() 进行移动。
MoveAndSlide(); // 同时,还会将下一帧移动值再次存入 Velocity,以实现平滑等效果。
架构:
状态机是事件“触发”机制,行为树是循环“轮询”机制。
游戏主角通常根据用户输入和有限状态机来控制,套招可上分层状态机,NPC则用行为树来实现AI自动化。
状态机:有限状态机(FSM/状态均平级/以模板 fsm-blend 项目为准)、分层有限状态机(HFSM/支持状态嵌套/死亡状态可中断其他任意状态)。
AnimationTree 节点 AnimationNodeStateMachine + state_started 信号或 a.TrackInsertKey(a.AddTrack(TrackType.Method),...),只能勉强用到无需_Process回调的NPC角色FSM。
行为树
编程语言:
C# 获取类名与Java的this.getClass()不同,使用 GD.Print(this.GetType()); 或 GD.Print(MethodBase.GetCurrentMethod().DeclaringType.Name);
GodotObject的GetClass()获取的是Godot内置类型(Node等),并非当前对象类型。
C# Lambda - var 变量可直接赋值无参 Lambda 表达式;若有参必须写上入参类型,想省略则要声明为 Action<string> 或 Func<int, int, int>。
Callable.From(Pressed) // 直接用方法名 public void Pressed() { GD.Print("pressed"); }
Callable.From((int index) => GD.Print(index)) // lambda表达式
Callable.From(delegate { GD.Print("pressed"); }) // 匿名委托
延迟调用:
Task.Delay(1000).ContinueWith(_ => { QueueFree(); }); // 或 await Task.Delay(3000);
var t = new Timer(); t.WaitTime = 3; t.OneShot = true; t.Autostart = true; // or t.Start();
t.Connect(Timer.SignalName.Timeout, Callable.From(() => { OS.Alert("timeout."); }));
p.AddChild(t); // GetTree().CreateTimer(3).Timeout += ()=>{ }; 无需添加但要 await/async。
延迟赋值:_hitBox.SetDeferred("monitoring", false);
延迟释放:
node.QueueFree(); await ToSignal(node, Node.SignalName.TreeExited);
跨平台:
JavaClassWrapper.wrap("android.os.Build$VERSION").SDK_INT
// 功能标签列表 - OS.has_feature("pc"); // 常用的有:mobile、web、windows、linux、macos、ios、debug
if (OS.HasFeature("android")) { Engine.GetSingleton("AndroidRuntime").Call("getActivity").AsGodotObject(); }
Engine.GetSingleton("AndroidRuntime").Call("getActivity").AsGodotObject().Call("getPackageManager").AsGodotObject()
.Call("hasSystemFeature", "com.google.android.play.feature.HPE_EXPERIENCE").AsBool();
原生对话框:DisplayServer.dialog_show(...) 比 ConfirmationDialog 交互体验更舒服。
DisplayServer.DialogShow("t", "d", new String[] { "b1", "b2" }, Callable.From((int buttonIndex) => GD.Print(buttonIndex)));
Android嵌入Godot库特性:
org.godotengine.godot.utils.DialogUtils.showSnackbar(...)、showDialog(...)
org.godotengine.godot.utils.Crypt.md5(String str)
org.godotengine.godot.utils.GodotNetUtils.getCACertificates()
org.godotengine.godot.utils.ProcessPhoenix - 作为Android Launcher应用时避免重启崩溃
图形卡API:
| 操作系统 |
Vulkan |
其他API |
| Windows |
✔ |
D3D12 |
| Linux |
✔ |
|
| Android |
✔ |
|
| macOS/iOS/iPadOS |
✔(通过MoltenVK模拟至Metal) |
Metal 3(A13/iOS 16/Godot 4.4+) |
Godot IDE 编辑器:
C# SDK 下载 - Windows 选 “.NET SDK x64”;macOS 选 “.NET SDK Arm64 (Apple Silicon)”,向导会自动决定安装路径,dotnet --info。
Godot编辑器 - 鼠标双击 macOS 的 Godot_v4.4-stable_mono_macos.universal.zip 会自动解压至当前目录 Godot_mono.app,故最好先将 *.zip 放到最终目录再解压。
导入:
综述 - 通常用Blender建模,导出glTF导进Godot。
建模 - 3D物体轮廓,不带外皮呈现。
材质 - 3D物体外皮的视觉效果,材质(material/光照交互)包含贴图(map/定位贴图),贴图包含纹理(texture/单纯位图);材质通常使用 基于物理的渲染(Physically Based Rendering , PBR)技术。
导出:
手机平台导出证书首选环境变量 或 .godot\export_credentials.cfg
各OS平台导出发布情况:
综述 - 导出模板用的是同一个,Godot IDE则每个平台1个。
Windows - Godot 最新版即可,渲染模式均可。
Android - aarch 架构用 Godot 最新版 + rendering_method="mobile";x86_64用 Godot 最新版 + rendering_method="gl_compatibility",若想用mobile模式只能回退至 Godot 4.4dev3 导出。
iOS - Godot 最新版即可,且必须在macOS中导出,Windows的导出按钮将永远处于置灰状态;“App Store 团队 ID”和“捆绑包标识符”为必填,故Xcode需要登录Apple Account。
测试设备 - iPhone11 iOS最新版;WeTest iOS云真机每分钟1元,起买60分钟,且要有能添加“UDID”至Devices列表的Apple开发者账号。
默认min_ios_version=14.0、driver.ios=metal,但可手动改为库最低支持的12.0 + 勾上 fallback_to_opengl3,导出后删除xcode项目中的MoltenVK库,【不确定】似乎还得 构建个不含Metal/Vulkan的导出模板。
导出模板和编辑器“One-click deploy”按钮可用任何渲染模式部署到真机,而一键部署到iOS模拟器则只能用gl_compatibility模式,即:iOS simulator does not support the Metal/Vulkan rendering driver。
iOS Simulator跑Metal和Vulkan报:Your GPU doesn't support image cube arrays...