C# 特征
本页概述了C#和Godot的常用特征以及它们如何一起使用.
类型转换和强制转换
C#是一种静态类型语言. 因此, 您无法执行以下操作:
var mySprite = GetNode("MySprite");
mySprite.SetFrame(0);
方法 GetNode()
返回一个 Node
实例. 在这种情况下, 你必须将其显式转换为所需的派生类型, Sprite
.
为此, 在C#中有多种选择.
强制转换和类型检查
如果返回的节点无法转换为Sprite, 则抛出 InvalidCastException
. 如果您非常确定它不会失败, 您可以使用它而不是 as
运算符.
Sprite mySprite = (Sprite)GetNode("MySprite");
mySprite.SetFrame(0);
使用AS运算符
如果节点无法转换为 Sprite
, 则 as
运算符返回 null
, 因此它不能与值类型一起使用.
Sprite mySprite = GetNode("MySprite") as Sprite;
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);
使用泛型方法
还提供了泛型方法以使该类型转换透明.
GetNode <T>()
在返回之前强制转换节点. 如果节点无法强制转换为所需类型, 它将抛出一个 InvalidCastException
.
Sprite mySprite = GetNode<Sprite>("MySprite");
mySprite.SetFrame(0);
GetNodeOrNull <T>()
使用 as
运算符, 如果节点无法强制转换为所需类型, 则返回 null
.
Sprite mySprite = GetNodeOrNull<Sprite>("MySprite");
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);
使用IS运算符进行类型检查
要检查节点是否可以强制转换为 Sprite
, 可以使用 is
运算符. 如果节点无法转换为 Sprite
, 则 is
运算符返回 false
, 否则返回 true
.
if (GetNode("MySprite") is Sprite)
{
// Yup, it's a sprite!
}
对于更高级的类型检查, 你可以查看 模式匹配.
C# 信号
有关完整的C#示例, 请参阅逐步 脚本语言 教程中的 处理信号 部分.
在C#中声明一个信号是通过一个 delegate
上的 [Signal]
特性完成的.
[Signal]
delegate void MySignal();
[Signal]
delegate void MySignalWithArguments(string foo, int bar);
这些信号可以在编辑器或者在代码中使用 Connect
进行连接. 如果想在编辑器中连接一个信号, 你需要(重新)生成项目组件才能看到这个新的信号. 生成操作可以点击 编辑窗口右上角的 “Build” 按钮手动触发.
public void MyCallback()
{
GD.Print("My callback!");
}
public void MyCallbackWithArguments(string foo, int bar)
{
GD.Print("My callback with: ", foo, " and ", bar, "!");
}
public void SomeFunction()
{
instance.Connect("MySignal", this, "MyCallback");
instance.Connect(nameof(MySignalWithArguments), this, "MyCallbackWithArguments");
}
发射信号是通过 EmitSignal
方法完成的.
public void SomeFunction()
{
EmitSignal(nameof(MySignal));
EmitSignal("MySignalWithArguments", "hello there", 28);
}
请注意, 你始终可以使用 nameof
关键字引用信号名称(应用于 委托(delegate)
本身).
在建立连接时,可以通过传递一个Godot数组来绑定值。
public int Value { get; private set; } = 0;
private void ModifyValue(int modifier)
{
Value += modifier;
}
public void SomeFunction()
{
var plusButton = (Button)GetNode("PlusButton");
var minusButton = (Button)GetNode("MinusButton");
plusButton.Connect("pressed", this, "ModifyValue", new Godot.Collections.Array { 1 });
minusButton.Connect("pressed", this, "ModifyValue", new Godot.Collections.Array { -1 });
}
信号支持所有 内置类型 的参数和绑定值, 以及从 Godot.Object 派生的类. 因此, 任何 Node
或 Reference
将自动兼容, 但是自定义数据对象将需要从 Godot.Object
或其子类之中扩展.
public class DataObject : Godot.Object
{
public string Field1 { get; set; }
public string Field2 { get; set; }
}
最后, 可以通过调用 AddUserSignal
来创建信号, 但要注意它应该在使用所述信号之前执行(使用 Connect
或 EmitSignal
).
public void SomeFunction()
{
AddUserSignal("MyOtherSignal");
EmitSignal("MyOtherSignal");
}
预处理器符号定义
为了能够根据目标编译环境改变 C# 代码,Godot 提供了一组符号定义。
备注
如果是Godot 3.2之前创建的项目, 你需要修改或重新生成你的 csproj 文件来使用这个功能(可与一个3.2+新项目中的 <DefineConstants>
相对比).
示例
例如, 你可以根据平台更改代码:
public override void _Ready()
{
#if GODOT_SERVER
// Don't try to load meshes or anything, this is a server!
LaunchServer();
#elif GODOT_32 || GODOT_MOBILE || GODOT_WEB
// Use simple objects when running on less powerful systems.
SpawnSimpleObjects();
#else
SpawnComplexObjects();
#endif
}
或者你可以检测代码所在的引擎, 这对于制作跨引擎库很有用:
public void MyPlatformPrinter()
{
#if GODOT
GD.Print("This is Godot.");
#elif UNITY_5_3_OR_NEWER
print("This is Unity.");
#else
throw new InvalidWorkflowException("Only Godot and Unity are supported.");
#endif
}
完整的定义列表
所有 Godot 项目都会定义
GODOT
。根据架构是 64 位还是 32 位,会定义
GODOT_64
或GODOT_32
。根据操作系统,会定义
GODOT_X11
、GODOT_WINDOWS
、GODOT_OSX
、GODOT_ANDROID
、GODOT_IOS
、GODOT_HTML5
、GODOT_SERVER
的其中之一,将来可能会更改这些名称。这些名称是根据 OS 单例的get_name()
方法创建的,但这个函数所能够返回的操作系统并不是都能够运行使用 Mono 的 Godot。
在 导出 时, 根据导出功能, 还可能定义以下内容:
GODOT_PC
,GODOT_MOBILE
或GODOT_WEB
中的一种, 取决于平台类型.GODOT_ARM64_V8A
或GODOT_ARMEABI_V7A
中的一个,仅在 Android 系统上,取决于架构。GODOT_ARM64
或GODOT_ARMV7
中的一个, 仅在iOS上, 取决于架构.GODOT_S3TC
,GODOT_ETC
和GODOT_ETC2
中的任一种, 取决于纹理压缩类型.所有在导出菜单中添加的自定义功能都会被大写并加上前缀:
foo
->GODOT_FOO
.
如果想要参考一个示例项目, 可以参考该OS测试demo:https://github.com/godotengine/godot-demo-projects/tree/master/misc/os_test