godot-csharp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGodot C# / .NET (4.x)
Godot C# / .NET (4.x)
Write Godot game code in C#: node subclasses, the engine lifecycle, exports, signals as
events, and GDScript interop. Targets Godot 4.3+ (.NET / C#); install the .NET SDK that
matches your Godot version — .NET 6.0 for 4.3/4.4, .NET 8 for 4.5+.
使用C#编写Godot游戏代码:节点子类、引擎生命周期、导出属性、将信号作为事件处理,以及与GDScript的互操作。适用于Godot 4.3+(.NET / C#);请安装与你的Godot版本匹配的.NET SDK——Godot 4.3/4.4对应**.NET 6.0**,Godot 4.5+对应**.NET 8**。
When to use
适用场景
- Use when scripting a Godot game in C# (+
.cs), translating GDScript idioms to C#, exposing.csprojfields, or wiring[Export]delegates and GetNode<T>.[Signal]
When not to use: GDScript-specific syntax → ; engine concepts that
are language-neutral (scenes, physics, animation) → the relevant skill. You need
the Godot .NET build + the .NET SDK installed; the standard build can't run C#.
godot-gdscriptgodot-*- 适用于使用C#编写Godot游戏脚本(+
.cs)、将GDScript惯用写法转换为C#、暴露.csproj字段,或是配置[Export]委托与GetNode<T>的场景。[Signal]
不适用场景:仅涉及GDScript特定语法的内容→参考;与语言无关的引擎概念(场景、物理、动画)→参考对应的技能。你需要安装Godot .NET版本以及.NET SDK;标准版本的Godot无法运行C#代码。
godot-gdscriptgodot-*Core workflow
核心工作流程
- Use the Godot .NET editor build and install the matching .NET SDK (.NET 6.0 for
Godot 4.3/4.4, .NET 8 for 4.5+). Creating the first C#
script generates a /
.csproj. Build with the editor or.sln.dotnet build - Every node script is a class extending a Godot type (the source generator relies on
partial). The file/class name should match the node script.partial - Override lifecycle methods in PascalCase with delta:
double,_Ready(),_Process(double delta)._PhysicsProcess(double delta) - Expose tunables with ; they show in the Inspector like GDScript
[Export].@export - Declare signals as delegates named
[Signal]; emit withXxxEventHandlerand subscribe with the generated C#EmitSignal(SignalName.Xxx, ...).event - Get nodes with (or
GetNode<T>("Path")), and call into GDScript with%Unique/Call/Getwhen needed.Set
- 使用Godot .NET编辑器版本并安装匹配的.NET SDK(Godot 4.3/4.4对应.NET 6.0,Godot 4.5+对应.NET 8)。创建第一个C#脚本时会生成/
.csproj文件。可通过编辑器或.sln命令进行构建。dotnet build - 每个节点脚本都是继承自Godot类型的类(源代码生成器依赖
partial关键字)。文件/类名应与节点脚本名称一致。partial - 以PascalCase命名重写生命周期方法,参数为类型的delta:
double、_Ready()、_Process(double delta)。_PhysicsProcess(double delta) - 使用暴露可调节参数;这些参数会像GDScript的
[Export]一样显示在检视面板中。@export - 将信号声明为委托,命名需以
[Signal]结尾;使用XxxEventHandler发送信号,并通过生成的C#EmitSignal(SignalName.Xxx, ...)订阅信号。event - 使用(或
GetNode<T>("Path"))获取节点,必要时通过%Unique/Call/Get调用GDScript代码。Set
Patterns
模式示例
1. A node script: lifecycle, [Export], GetNode<T>
1. 节点脚本:生命周期、[Export]、GetNode<T>
csharp
using Godot;
public partial class Player : CharacterBody2D
{
[Export] public float Speed = 200.0f; // editable in the Inspector
[Export] public float JumpVelocity = -400.0f;
private const float Gravity = 1200.0f;
private AnimatedSprite2D _sprite;
public override void _Ready()
{
_sprite = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
}
public override void _PhysicsProcess(double delta)
{
Vector2 v = Velocity; // Velocity is a property here
if (!IsOnFloor())
v.Y += Gravity * (float)delta; // delta is double; cast for float math
if (Input.IsActionJustPressed("jump") && IsOnFloor())
v.Y = JumpVelocity;
float dir = Input.GetAxis("move_left", "move_right");
v.X = dir != 0 ? dir * Speed : Mathf.MoveToward(v.X, 0, Speed);
Velocity = v;
MoveAndSlide(); // no args, like GDScript 4.x
}
}csharp
using Godot;
public partial class Player : CharacterBody2D
{
[Export] public float Speed = 200.0f; // editable in the Inspector
[Export] public float JumpVelocity = -400.0f;
private const float Gravity = 1200.0f;
private AnimatedSprite2D _sprite;
public override void _Ready()
{
_sprite = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
}
public override void _PhysicsProcess(double delta)
{
Vector2 v = Velocity; // Velocity is a property here
if (!IsOnFloor())
v.Y += Gravity * (float)delta; // delta is double; cast for float math
if (Input.IsActionJustPressed("jump") && IsOnFloor())
v.Y = JumpVelocity;
float dir = Input.GetAxis("move_left", "move_right");
v.X = dir != 0 ? dir * Speed : Mathf.MoveToward(v.X, 0, Speed);
Velocity = v;
MoveAndSlide(); // no args, like GDScript 4.x
}
}2. Signals as C# events
2. 将信号作为C#事件使用
csharp
using Godot;
public partial class Health : Node
{
// Delegate name MUST end with "EventHandler"; generator creates the event + SignalName.
[Signal] public delegate void HealthChangedEventHandler(int current, int max);
private int _hp = 100;
public void TakeDamage(int amount)
{
_hp = Mathf.Max(_hp - amount, 0);
EmitSignal(SignalName.HealthChanged, _hp, 100); // type-safe signal name
}
public override void _Ready()
{
HealthChanged += OnHealthChanged; // subscribe like a normal C# event
}
private void OnHealthChanged(int current, int max) => GD.Print($"HP {current}/{max}");
}csharp
using Godot;
public partial class Health : Node
{
// Delegate name MUST end with "EventHandler"; generator creates the event + SignalName.
[Signal] public delegate void HealthChangedEventHandler(int current, int max);
private int _hp = 100;
public void TakeDamage(int amount)
{
_hp = Mathf.Max(_hp - amount, 0);
EmitSignal(SignalName.HealthChanged, _hp, 100); // type-safe signal name
}
public override void _Ready()
{
HealthChanged += OnHealthChanged; // subscribe like a normal C# event
}
private void OnHealthChanged(int current, int max) => GD.Print($"HP {current}/{max}");
}3. Instancing a scene in C#
3. 在C#中实例化场景
csharp
public partial class Spawner : Node2D
{
// Load once; PackedScene is the C# equivalent of preload's result.
private readonly PackedScene _bullet = GD.Load<PackedScene>("res://bullet.tscn");
public void Shoot(Vector2 at)
{
var b = _bullet.Instantiate<Node2D>(); // typed instantiate
b.GlobalPosition = at;
AddChild(b);
}
}csharp
public partial class Spawner : Node2D
{
// Load once; PackedScene is the C# equivalent of preload's result.
private readonly PackedScene _bullet = GD.Load<PackedScene>("res://bullet.tscn");
public void Shoot(Vector2 at)
{
var b = _bullet.Instantiate<Node2D>(); // typed instantiate
b.GlobalPosition = at;
AddChild(b);
}
}4. Interop with GDScript nodes
4. 与GDScript节点互操作
csharp
public override void _Ready()
{
Node gd = GetNode("GDScriptNode");
// Call a GDScript method and read/write its properties dynamically.
gd.Call("take_damage", 10);
int score = (int)gd.Get("score");
gd.Set("score", score + 5);
// Connect to a GDScript signal by name:
gd.Connect("died", Callable.From(OnDied));
}
private void OnDied() => GD.Print("entity died");csharp
public override void _Ready()
{
Node gd = GetNode("GDScriptNode");
// Call a GDScript method and read/write its properties dynamically.
gd.Call("take_damage", 10);
int score = (int)gd.Get("score");
gd.Set("score", score + 5);
// Connect to a GDScript signal by name:
gd.Connect("died", Callable.From(OnDied));
}
private void OnDied() => GD.Print("entity died");Pitfalls
常见陷阱
- Forgetting . Without
partial, the Godot source generator can't extend the class andpartial/[Export]break with confusing build errors.[Signal] - Wrong method case/signature. C# overrides are ,
_Ready,_Process(double)— PascalCase and_PhysicsProcess(double)delta (GDScript uses snake_case anddouble). A mismatched name just won't be called.float - delegate naming. It must end with
[Signal]; the engine exposes the signal as the name without that suffix and generatesEventHandlerand a C#SignalName.X.event - vs
GD.Print. UseConsole.WriteLine/GD.Printto reach the Godot output panel;GD.PrintErroutput may not appear.Console - Value-type structs. ,
Vector2,Colorare structs — mutate a local copy (Transform2D); editingvar v = Velocity; v.X = ...; Velocity = v;directly won't compile/persist.Velocity.X - Needs the .NET build + SDK. The non-.NET editor can't run C#; mismatched/missing .NET SDK causes build failures. Match the SDK to the Godot version (4.3/4.4 → .NET 6.0, 4.5+ → .NET 8; Android export on 4.5 needs .NET 9).
- vs
QueueFree()— same rules as GDScript; preferFree(). Disposed objects throwQueueFree()if used after freeing.ObjectDisposedException - Export to some platforms differs for .NET (e.g. extra steps for web/mobile); check the .NET export notes for your target.
- 忘记添加关键字。如果没有
partial,Godot源代码生成器无法扩展该类,partial/[Export]会出现难以理解的构建错误。[Signal] - 方法命名/签名错误。C#中的重写方法为、
_Ready、_Process(double)——采用PascalCase命名且delta参数为_PhysicsProcess(double)类型(GDScript使用蛇形命名法和double类型)。命名不匹配的方法不会被调用。float - 委托命名错误。委托名称必须以
[Signal]结尾;引擎会将信号暴露为去掉该后缀的名称,并生成EventHandler和对应的C#SignalName.X。event - 与
GD.Print的区别。使用Console.WriteLine/GD.Print输出到Godot的面板;GD.PrintErr的输出可能无法显示。Console - 值类型结构体。、
Vector2、Color都是结构体——需要修改本地副本(Transform2D);直接修改var v = Velocity; v.X = ...; Velocity = v;无法编译或生效。Velocity.X - 需要.NET版本的Godot和对应SDK。非.NET版本的编辑器无法运行C#代码;SDK版本不匹配或缺失会导致构建失败。请确保SDK版本与Godot版本匹配(4.3/4.4→.NET 6.0,4.5+→.NET 8;4.5版本导出Android需要.NET 9)。
- 与
QueueFree()的区别——规则与GDScript一致;优先使用Free()。释放后的对象如果被再次使用会抛出QueueFree()异常。ObjectDisposedException - .NET版本导出部分平台的流程不同(例如Web/移动端需要额外步骤);请查看目标平台的.NET导出说明。
References
参考资料
- For export attribute variants (, ranges, typed arrays), async with
[ExportGroup],await ToSignal(...)vs System collections, custom Resources in C#, and project/build setup, readGodot.Collections.references/csharp-setup-and-interop.md
- 关于导出属性的变体(、范围、类型化数组)、使用
[ExportGroup]实现异步、await ToSignal(...)与系统集合的区别、C#中的自定义资源,以及项目/构建配置,请阅读Godot.Collections。references/csharp-setup-and-interop.md
Related skills
相关技能
- — the GDScript equivalents of these patterns.
godot-gdscript - — signal/event architecture (language-neutral).
godot-signals-groups - — data resources; the C#
godot-resources+[Export]pattern.Resource - — C# in Unity, for developers coming from there.
unity-csharp-scripting
- ——这些模式对应的GDScript实现。
godot-gdscript - ——信号/事件架构(与语言无关)。
godot-signals-groups - ——数据资源;C#中的
godot-resources+[Export]模式。Resource - ——Unity中的C#脚本开发,供有Unity开发经验的开发者参考。
unity-csharp-scripting