Godot C#/Mono 语法制作游戏 - Library、JSON、File IO、信号
Godot C#/Mono 语法制作游戏
Godot核心 | Godot官方文档 | Godot源码 | Godot Shaders 着色器 | 产品发布检查清单 | 游戏开发专题
核心
综合: 常用 - OS.get_tmp_dir()、FileAccess.create_tmp(FileAccess.WRITE_READ, ".txt") 存档 - 存档前在内存计算出校验Hash值 https://docs.godotengine.org/zh-cn/4.x/classes/class_hashingcontext.html SDK: Godot SDK文件路径 - GodotSharp\Tools\nupkgs\Godot.NET.Sdk.4.3.0.nupkg Godot NuGet离线包创建和使用: mkdir ~/new-project/ cd ~/new-project/ rm -r ~/new-project/* 目标框架 https://learn.microsoft.com/zh-cn/dotnet/standard/frameworks -f指定的必须是本机已安装.NET SDK版本,手动改*.csproj则不需要安装。 dotnet new classlib --no-restore 等更换为Godot SDK后再还原。 Godot项目SDK需要手动更换: <Project Sdk="Godot.NET.Sdk/4.3.0"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <RestoreAdditionalProjectSources>$(MSBuildThisFileDirectory)/../temp/local-nuget/; D:\main\person\projects\temp\local-nuget</RestoreAdditionalProjectSources> ... [测试下] dotnet build 构建命令(取自Godot IDE选项卡MSBuild构建选项): dotnet build -c Debug -p:GodotTargetPlatform=windows code -n ~/new-project/ 说明 - *.nupkg本质是zip文件,且字节码dll不区分x64等平台: GodotSharp.4.3.0.nupkg\lib\net6.0\GodotSharp.dll dotnet pack -c Release dotnet nuget push ".godot\mono\temp\bin\Release\x.1.0.0.nupkg" --api-key YOUR_GITHUB_PAT --source "https://nuget.pkg.github.com/iwangxiaodong/index.json" 默认为Private,可在 Package settings -> Change package visibility 手动改为 Public,注意 Public 只是指能对外看到,但拉取时还需要指定 --api-key 。 mkdir ~/nuget-fallback/ 或 mkdir D:\main\person\projects\temp\local-nuget cp ~/new-project\bin\Release\new-project.1.0.0.nupkg ~/local-nuget/ 或 cp .godot\mono\temp\bin\Release\x.1.0.0.nupkg D:\main\person\projects\temp\local-nuget ls ~/local-nuget/ x.csproj 指定本地源目录用 RestoreAdditionalProjectSources,见上方配置。 测试拉取包 dotnet add package new-project <ItemGroup><PackageReference Include="x-y-z" Version="1.0.0" /></ItemGroup> 重新打包后必须删除 C:\Users\person\.nuget\packages\godot-project-csharp-library\ 方生效,[可选删]C:\Users\person\AppData\Local\Temp\MetadataAsSource\;后续研究如何自动处理。 【可选】在项目目录或任意上级目录定义个 nuget.config。 说明 - 可填入私有包验证信息;配置更改后应删除.godot目录使其生效? 支持包文件格式:{id-lowercase}.{version-lowercase}.nupkg<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="local" value="D:\main\person\projects\temp\local-nuget" /> </packageSources> </configuration>[其他项目使用] dotnet nuget list source 注意 - 添加时不能使用~/写法 [未测] <RestoreAdditionalProjectFallbackFolders>$(MSBuildThisFileDirectory)/../temp/nuget-fallback/; D:\main\person\projects\temp\nuget-fallback</RestoreAdditionalProjectFallbackFolders> 回退目录环境变量(无默认值) - NUGET_FALLBACK_PACKAGES 或 dotnet nuget add source -n local-nuget-fallback D:\main\person\projects\temp\nuget-fallback dotnet nuget remove source 'local-nuget-fallback'
IO
JSON: var v = Json.ParseString(rs); //var j = new Json(); j.Parse("{}"); GD.Print(j.Data); // 不支持C#的as转换 - v as Godot.Collections.Dictionary; var dict = v.As<Godot.Collections.Dictionary>(); GD.Print(dict); if (dict != null && dict.ContainsKey("msg")) { GD.Print(dict["msg"].As<string>()); } 读取图片文件: Image.LoadFromFile(@"D:\temp\x.jpg")
信号
信号: IsConnected无法判断“+=”方式连接的信号,但Connect(...)方式的则判定正确。 C# nameof(method)效果等同Godot MethodName.method 信号增加尾参:注意 - 只有GDScript才有bind方法! var t:Timer=get_node("Timer"); #t.one_shot=true; t.timeout.connect(Callable(self,"m").bind(123)); t.start() 解决C#的Lambda中无法使用-=取消连接信号的语法限制: 首选 IsConnected判断方式避免重复连接; 或 ap.AnimationFinished += (sn) => { var list = ap.GetSignalConnectionList(AnimationPlayer.SignalName.AnimationFinished); foreach (var dict in list) // signal、callable、flags { ap.Disconnect(AnimationPlayer.SignalName.AnimationFinished, (Callable)dict["callable"]); } }; ap.Play("Idle"); 或 一次性连接信号 - ap.Connect(AnimationPlayer.SignalName.AnimationFinished, new Callable(this, MethodName.xxx), (uint)ConnectFlags.OneShot); 示例: [Tool] public partial class MyNode : Node { [ExportToolButton("Click me!")] public Callable ClickMeButton => Callable.From(ClickMe); public void ClickMe() { GD.Print("Hooray!"); } }
其他
按权重随机(刷装备等) - https://docs.godotengine.org/zh-cn/4.x/classes/class_randomnumbergenerator.html#class-randomnumbergenerator-method-rand-weighted 登记到下一帧回调首行,执行后自动断开(与call_deferred组成1头1尾的执行时机): get_tree().process_frame.connect(callable, CONNECT_ONE_SHOT) 树形场景: 节点可以直接new出来并add;或通过持有id来获取 GodotObject.InstanceFromId(id) 首选GD.Load方法;次选比GD.Load多一个CacheMode.Reuse参数的ResourceLoader.Load; 异步载入用ResourceLoader.LoadThreadedRequest("res://s.tscn"); 轮询后取用 if (ResourceLoader.LoadThreadedGetStatus("res://s.tscn") == ThreadLoadStatus.Loaded){ ResourceLoader.LoadThreadedGet("res://s.tscn"); } 调用Load返回预载入(首次缓存)PackedScene,ps.Dispose()或ps.Free()释放缓存;执行ps.Instantiate()后则返回可使用的node了。 节点分类: 单独使用 - Button、MeshInstance3D等 组合使用 - CharacterBody3D需要子节点CollisionShape3D来提供碰撞,需要MeshInstance3D等提供可见性,后两者为同级; 因MeshInstance3D无IsOnFloor()碰撞判断,且只提供可见性,故无法单独与CollisionShape3D搭配使用,可换用RigidBody3D。