从此
📄文章 #️⃣专题 🌐酷站 👨‍💻技术 📺 📱

游戏引擎IDE编辑器、UI控件布局、画面分辨率、导出模板、热更新插件、PCK/Patch、SDK库 API文档

综合

  Godot - 读作“戈哦斗欧”,t不发音。

  Godot 下载 - https://downloads.tuxfamily.org/godotengine/  或官网(被墙) - https://godotengine.org

  Godot 每日构建下载 | Godot SDK Projects

  Godot IDE 窗口卡住或闪退的,可加参数来查看报错输出:./Godot_v4.x_mono_win64.exe -v
  对于不支持 Vulkan 的老旧显卡,可以加降级参数来启动:./Godot_v4.x_mono_win64.exe --rendering-driver opengl3

  Godot IDE 编辑器设置配置文件 - C:\Users\person\AppData\Roaming\Godot\editor_settings-4.3.tres
  Godot IDE “项目设置”窗口点亮“高级设置”之后才会显示额外配置项。

  ICON - https://github.com/electron/rcedit  Editor→Editor Settings→Export→Windows 指定 E:/game-dev/rcedit-x64.exe
         可抑制警告 - WARNING: 资源修改: 无法启动 rcedit 可执行文件。 

  资源 - 内置支持的音频格式为*.ogg(AudioStreamOggVorbis)、*.wav(AudioStreamPlayer),视频格式为*.ogv;*.mp3不支持?

  Windows导出*.exe时软件名称为“Godot Engine”,且icon也是默认的,想修改的话可配置工具(编辑器设置→导出→Windows):
   下载 https://github.com/electron/rcedit
   鼠标悬浮会显示“文件描述/application/file_description”值,“产品名称”也可以顺带改下。

Godot编程

Godot IDE 若报 UNUSED_PARAMETER - The parameter "delta" is never used in the function "_process()". If this is intended, prefix it with an underscore: "_delta".
  是指若不使用入参,可加下划线前缀来抑制该警告:_process(_delta)

x.tscn格式:
  [node name="NodeName" parent="." instance=ExtResource("1_234az")]
  说明 - 未写名type="Node3D"的node,会从instance值关联资源的type="通常为PackedScene或Material"来确定节点类型,IDE悬浮显示的类型则取自该关联资源的root节点type。

Godot UI - 布局、控件、Node2D

综合:
  IDE默认的分辨率过于保守,尺寸为1152×648 见源码;故首选移动端的 1280×720,而PC则为 steam使用率最多分辨率 的 1920 x 1080。

  只有Control处于焦点时才会触发_gui_input,而不用更早触发的全局_input。

Node2D:
  基于锚点(pivot_offset、anchor_...)定位

Control:
  基于左上角定位

Node3D:
  基于中心点定位

RichTextLabel v4.4+支持了水平居中对齐VERTICAL_ALIGNMENT_CENTER。

插件

  Godot Git Plugin:
    Godot Git插件 已支持到v4.4,或用git命令行或VS Code控制源码。
    已知问题 - 
      电脑:No suitable library found for GDExtension: res://addons/godot-git-plugin/git_plugin.gdextension. Possible feature flags for your platform...
      安卓:USER ERROR: Failed loading resource: res://addons/godot-git-plugin/git_plugin.gdextension
      排除:导出 -> 资源 -> 从项目中排除 exclude_filter="addons/godot-git-plugin/*"  参考 https://github.com/godotengine/godot-git-plugin/issues/77
      解决:虽报错但不阻止游戏启动,若想抑制报错 - Godot 4.4dev6已根据exclude_filter来抑制报错 - https://github.com/godotengine/godot/pull/97216; 或打包前用MSBUILD或手动删除 .godot\extension_list.cfg
        

    IDE -> AssetLib 搜“git”或“Godot Git Plugin”,自动安装至项目根目录/addons/下
    【或】手动抽取 godot-git-plugin-v3.1.0.zip 至项目 res://addons/godot-git-plugin/plugin.cfg
    忽略addons目录 或 插件软链接【管理员身份】: 注意-Target路径结尾不能存在斜杠,以免git命令和git库识别不一。
      New-Item -ItemType SymbolicLink -Path ./addons/ -Target E:\godot-git-plugin-v3.1.0\godot-git-plugin-v3.1.0\addons
      或只软链接较大插件(30MiB+):New-Item -ItemType SymbolicLink -Path ./addons/godot-git-plugin/ -Target E:\game-dev\godot-git-plugin-v3.1.1\godot-git-plugin-v3.1.1\addons\godot-git-plugin

    注意 - Open Project > Version Control > 创建版本控制元数据; 该操作仅生成或重置已配置好的.gitignore文件;
    用法(不支持中文路径) - Open Project > Version Control > Version Control Settings > 勾上“连接到VCS”;
      该面板Password值在IDE重启后清空;若想存储可考虑用GODOT_GIT_PASSWORD环境变量(官方还未做好):[Environment]::SetEnvironmentVariable("GODOT_GIT_PASSWORD", "[github password...]", 'User')
      之后IDE右侧属性面板会增加一个Commit面板;添加至“Staged Changes”面板其实等同执行 git add . 命令,并不是 git stash 命令。

      追加至 .gitignore 文件:注意不带斜杠的addons是软链接文件,非目录。
.godot/
addons/godot-git-plugin/
# 软链接路径
addons/godot-git-plugin
android/

      且提交前必须执行以下命令行:
        git config --global user.name "your name"
        git config --global user.email "you@example.com"
      Push前还要点面板右下角三个点菜单 -> 新建远程仓库 - Name: origin   URL: https://github.com/you/repo.git

  Windows操作Godot项目提示文件名过长,可通过删除.godot/文件夹解决。

  Godot项目改名:
    [application]
    config/name="x"
    程序集名可选:
      [dotnet]
      project/assembly_name="x"
    VS项目名可选:
      x.csproj中x
      x.sln中Project("{...}") = "x", "x.csproj", "{...}"

  Godot识别USD插件 - https://github.com/V-Sekai/godot-usd  内部用了pip install bpy库的bpy.ops.export_scene.gltf(...)
  Godot加载gltf格式3D模型 - new GLTFDocument().append_from_file("/path/to/file.gltf", gltf_state_load)
  Godot播放MP4视频(VideoStreamPlayer仅支持*.ogv) - https://zhuanlan.zhihu.com/p/657396670
  Godot图片绑定骨骼制作2D动画工具(比关键帧动画尺寸小) - https://zh.esotericsoftware.com/spine-godot

Godot C#/Mono 外置IDE

      VS Code: 也支持无跟踪隐私的VS Codium
        安装 ms-dotnettools.csharp 扩展
        Godot -> 编辑器设置 -> 高级设置 -> .NET -> Editor -> External Editor 为 Visual Studio Code and VSCodium;
        VS Code:
          在VS Code运行选项卡,创建 launch.json 文件时从下拉菜单中选择 C# Godot,
          运行Godot IDE并打开游戏项目等待被控制,
          此时运行VSCode的Play in Editor会控制Godot IDE窗体进入调试模式。
        [可选] launch.json的“Launch”配置项改成真实路径可无需打开GodotIDE:
          "executable": "D:\\x\\Godot_v3.3.2-stable_mono_win64.exe",
        [可选] launch.json的“Attach”配置未测

      VS Code -> Trusted Folders & Workspaces:启用后C#智能感知等能力才可用,非系统防病毒排除项。
        完全信任 - Settings -> security.workspace.trust.enabled -> 去除勾选

      VS Code依赖库管理 - 使用命令行(NuGet Package Manager必须翻墙):
        dotnet add package NLog -v 4.6.7

Godot - 独立开发者游戏引擎


C#:

        // 默认不编译已存在C#文件,必须触发下: Godot IDE -> 项目 -> 工具 -> Create C# solution 或 添加脚本 -> 语言 C# -> 创建
        using Godot;
        using System;
        // Godot脚本类必须使用partial修饰符
        public partial class MyScript : Node3D // 2D : Node
        {
            [Export] // 使其出现在Godot IDE属性面板
            private Godot.Collections.Array Array;

            [Export(PropertyHint.MultilineText)]
            string Text { get; set; } // 控制C#属性的读写

            public override void _Ready()
            {
              //	打印行数等堆栈信息
              GD.Print(System.Environment.StackTrace);

              //	绝对原点 - IDE 3D默认视图 - 后、右、顶
              GD.Print(Vector3.Zero);
              //	绝对朝向 - 物体朝向观众或摄像头的那一面,即IDE的3D后视图
              GD.Print(new Basis(1, 0, 0, 0, 1, 0, 0, 0, 1));
              //	全局距离 - 相对于绝对原点的远近;即3D视图中心
              GD.Print(this.GlobalTransform.Origin);
              //	全局方向 - 相对于绝对正面的方向
              GD.Print(this.GlobalTransform.Basis);
              //	相对于父节点距离 - 0或实际米数;即物体中心
              GD.Print(this.Transform.Origin);
              //	相对于父节点方向 - 索引值只能0或1
              GD.Print(this.Basis); // 等同this.Transform.Basis
            }
            public const int MOVE_SPEED = 300;
            public override void _Process(double delta)
            { // MoveToward 方法移动可解决瞬移问题; 或换用更常用的 MoveAndSlide();
              this.Position = new Vector2(GetGlobalMousePosition().X, this.Position.Y);
              this.Position = this.Position.MoveToward(new Vector2(200, 200), (float)delta * MOVE_SPEED);
            }
        }        
    


GDScript:

extends Node

func _ready():
	pass

func _process(delta):
	pass
    

Godot游戏引擎3D/WASD移动模板实例

Godot 3D上下楼梯控制
最简单可用CollisionShape3D的SeparationRayShape3D,可通过旋转调整发射方向,原理是射线遇到障碍物后,从末端推挤自身碰撞区至离发射端最近的碰撞点 - https://github.com/Griiimon/CharacterBody-On-Stairs
或等待提案 https://github.com/godotengine/godot-proposals/issues/2751

Godot游戏引擎2D顶视图八向移动自由转向示例

Godot游戏引擎2D横板左右跳蹲+重力示例


Godot游戏引擎手机端虚拟摇杆

Godot游戏引擎手机端虚拟摇杆(已插件化)
用IDE内部安装会覆盖根目录README.md文件,故应手动下载并放入res://addons/virtual_joystick/。用法视频
虚拟摇杆插件用法实例(MeshInstance3D或Sprite2D脚本中):
	public override void _PhysicsProcess(double delta)
	{ MoveAndSlide(); } // 注册analogic_chage(move: Vector2)信号

	void _on_virtual_joystick_analogic_chage(Vector2 v2)
	{ GD.Print(v2); Velocity = v2 * Speed; } // float Speed = 300.0f;

        // 3D Vector3用法:
	Vector3 direction = Vector3.Zero;
        // 为兼容pc+mobile而归零:_PhysicsProcess 底部追加 if (OS.HasFeature("pc")){ direction = Vector3.Zero; }
	void _on_virtual_joystick_analogic_chage(Vector2 v2)
	{ direction = new Vector3(v2.X, Vector3.Zero.Z, v2.Y); }

Godot已知问题、反直觉情况

  Godot项目支持Windows长路径,但导出Windows程序时却报错,临时解决办法是:导出盘符不要跟项目盘符一样;
    另外报 Safe save failed 也是该问题所致,即保存 Shader Cache 时会在 .godot/shader_cache/SceneForwardMobileShaderRD/ 目录创建超长的目录名,可升级至解除限制的Godot 4.4,或通过 编辑器设置->文件系统->保存时->勾掉 Safe Save...。
  非 .godot/ 目录报 Safe save failed 解决: Add-MpPreference -ExclusionPath "$env:userprofile\AppData\Local\Godot\"

Godot 3.x升级至4.x差异

  C#包内dll可通过ILSpy反编译查看其类库

  _Process(float delta) 改为 _Process(double delta);同样适用于 _PhysicsProcess(double delta)
  GetViewport().Size 改为 GetWindow().Size 注意 - Window类是v4.0新增。
  vector2.x、vector2.y 改为 vector2.X、vector2.Y
  packedScene.Instance(); 改为 packedScene.Instantiate();
  GetTree().ChangeScene("res://x.tscn"); 改为 GetTree().ChangeSceneToFile("res://x.tscn");
  (int)ButtonList.Left 改为 MouseButton.Left
  Input.IsKeyPressed((int)KeyList.A) 改为 Input.IsKeyPressed(Key.A)
  inputEventKey.Scancode 改为了 inputEventKey.Keycode
  btn.Connect("pressed",this,"OnMethod"); 改为 btn.Pressed += OnMethod; 或 btn.Connect(Button.SignalName.Pressed, new Callable(this, "OnMethod")); 或不用this:Callable.From(OnMethod)
  信号回调宽容的入参类型 _on_area_entered(object obj) 改为 强类型的 _on_area_entered(Area2D a)


  其他变动:
    GetNode("AnimationPlayer").PlaybackSpeed 改为 animationPlayer.SpeedScale
    kinematicCollision.Collider 改为 kinematicCollision3D.GetCollider();适用于 collision.GetNormal()
    characterBody3D.GetSlideCount() 改为 characterBody3D.GetSlideCollisionCount()
    characterBody3D.Transform3D 改为 Transform
    control.RectPosition 改为 control.Position

    GD.RandfRange(0.9, 1.1) 改为 GD.RandRange(0.9, 1.1); 或(不确定) var rng = new RandomNumberGenerator(); rng.Randomize(); rng.RandfRange((float)0.9, (float)1.1); //入参从double变float

Godot插件开发

综合:
  插件内获取导出项名字 - self.get_option("version/code") 
    self 类型为 EditorExportPlugin 而非入参对象 platform.get_option("package/unique_name")

GDS插件:
  导出时决定是否包含插件aar和依赖库:
	# 只有 EditorExportPlatformAndroid 入参 platform.get_os_name()=="Android" 才会调用
	func _get_android_dependencies(platform, debug):
		if self.get_option("package/unique_name").ends_with(".fullchannel"):
			return PackedStringArray(["com.openle.module:aos:1.0.0-SNAPSHOT","com.openle.module:core:1.0.0-SNAPSHOT"])
			#return PackedStringArray(["_plugin_name/p-release.aar"]) # for _get_android_libraries(platform, debug)
		return PackedStringArray()

  导出时下载aar文件:
	func _get_android_libraries(platform, debug):
		var hr = HTTPRequest.new()
		Engine.get_main_loop().root.add_child(hr)
		hr.request("https://congci.com/.well-known/static/images/core/logo.svg")
		var r=(await hr.request_completed)[3]
		print(r.get_string_from_utf8())

		return PackedStringArray(["x.aar"])


  导出时添加额外配置文件:
	func _export_begin(features: PackedStringArray, is_debug: bool, path: String, flags: int):
		var json=("{\"versionCode\":" + str(self.get_option("version/code")) + "}");
		add_file("res://export-plugin-gen.json", json.to_utf8_buffer(), false)
                #add_file("res://gen.bytes",PackedByteArray(),false)

  覆盖导出项:
	func _get_export_options_overrides(platform) -> Dictionary:
		return {
			"binary_format/embed_pck": true,
		}

EditorPlugin在IDE“文件系统”右键增加菜单项:
func _enter_tree(): # EditorPlugin var plugin = preload("res://addons/OurGameCore/menu.gd").new() add_context_menu_plugin(EditorContextMenuPlugin.CONTEXT_SLOT_FILESYSTEM, plugin) # menu.gd extends EditorContextMenuPlugin func _popup_menu(paths): var pm = PopupMenu.new() pm.add_item("SubMenu",1) pm.add_item("SubMenu2",2) pm.id_pressed.connect(func(ids):print(ids)) add_context_submenu_item("TopMenu",pm) #add_context_menu_item("TopMenu",func(resPaths):print(resPaths))

Godot OTA

Godot游戏OTA、PCK、MOD、Patch基本概念

动态PCK:  
  说明 - PCK项目不需要主场景和类,导出选项最好不要勾上“Runnable/可执行的”,“导出 PCK/ZIP”首选紧凑的*.pck后缀。
  var bytes = Godot.FileAccess.GetFileAsBytes("res://ExportingProject.dll");
  var asm = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).LoadFromStream(new MemoryStream(bytes));
  ScriptManagerBridge.LookupScriptsInAssembly(asm);
  // GDS则只需要以下1行即可:
  var ok = ProjectSettings.LoadResourcePack("res://ExportingProject.pck");

其他

Godot IDE新建脚本时勾上“Built-in Script”可将代码嵌入到*.tscn中,但不支持C#。

Godot节点各种移动方式 - https://godotlearn.com/godot-3-1-how-to-move-objects/

文档生成时通过环境变量指定语言:SPHINXOPTS="-D language=zh-CN"
  教程 - https://docs.godotengine.org/en/latest/contributing/documentation/building_the_manual.html