Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

C# 导出属性

在 Godot 中可以导出类成员。这意味着它们的值会与它们所附加的资源(例如场景)一起保存。它们也可以在属性编辑器中进行编辑。导出使用特性 [Export] 来完成。

using Godot;

public partial class ExportExample : Node3D
{
    [Export]
    public int Number { get; set; } = 5;
}

在这个例子中,数值 5 将被保存,在构建当前项目后,它将在属性编辑器中可见。

导出成员变量的基本好处之一,便是让这些变量在编辑器中可见可改,这样一来,美术师和游戏设计师就可以修改这些会影响程序运行方式的值。为此,Godot 提供了一种特殊的导出语法。

Exporting can only be done with Variant 兼容类型.

备注

GDScript 中也能够导出属性,相关信息见 GDScript 导出属性

基本用法

Exporting works with fields and properties. They can have any access modifier.

[Export]
private int _number;

[Export]
public int Number { get; set; }

导出的成员可以指定默认值;否则,将使用类型的 默认值

An int like Number defaults to 0. Text defaults to null because string is a reference type.

[Export]
public int Number { get; set; }

[Export]
public string Text { get; set; }

Default values can be specified for fields and properties.

[Export]
private string _greeting = "Hello World";

[Export]
public string Greeting { get; set; } = "Hello World";

Properties with a backing field use the default value of the backing field.

private int _number = 2;

[Export]
public int NumberWithBackingField
{
    get => _number;
    set => _number = value;
}

备注

A property's get is not actually executed to determine the default value. Instead, Godot analyzes the C# source code. This works fine for most cases, such as the examples on this page. However, some properties are too complex for the analyzer to understand.

For example, the following property attempts to use math to display the default value as 5 in the property editor, but it doesn't work:

[Export]
public int NumberWithBackingField
{
    get => _number + 3;
    set => _number = value - 3;
}

private int _number = 2;

The analyzer doesn't understand this code and falls back to the default value for int, 0. However, when running the scene or inspecting a node with an attached tool script, _number will be 2, and NumberWithBackingField will return 5. This difference may cause confusing behavior. To avoid this, don't use complex properties. Alternatively, if the default value can be explicitly specified, it can be overridden with the _PropertyCanRevert() and _PropertyGetRevert() methods.

Any type of Resource or Node can be exported. The property editor shows a user-friendly assignment dialog for these types. This can be used instead of GD.Load and GetNode. See Nodes and Resources.

[Export]
public PackedScene PackedScene { get; set; }

[Export]
public RigidBody2D RigidBody2D { get; set; }

导出分组

可以使用 [ExportGroup] 特性将导出的属性分组显示在检视器中。在此特性之后的每个导出的属性都将添加到该组中。开始一个新组,或使用 [ExportGroup("")] 进行分组结束。

[ExportGroup("My Properties")]
[Export]
public int Number { get; set; } = 3;

该特性的第二个参数可用于仅将具有指定前缀的属性分组。

分组可以嵌套,请使用 [ExportSubgroup] 在分组中创建子分组。

[ExportSubgroup("Extra Properties")]
[Export]
public string Text { get; set; } = "";
[Export]
public bool Flag { get; set; } = false;

你也可以修改你的主分类的名称,或者在属性列表中使用 [ExportCategory] 特性创建额外的分类。

[ExportCategory("Main Category")]
[Export]
public int Number { get; set; } = 3;
[Export]
public string Text { get; set; } = "";

[ExportCategory("Extra Category")]
[Export]
public bool Flag { get; set; } = false;

备注

属性列表是根据类继承来组织的,而新的分类会打破这种预期。使用它们时要小心,尤其是在创建公共项目时。

字符串用作文件路径

属性提示可以用来导出字符串作为路径

字符串可以用作文件路径。

[Export(PropertyHint.File)]
public string GameFile { get; set; }

字符串也可以用作文件目录路径。

[Export(PropertyHint.Dir)]
public string GameDirectory { get; set; }

字符串在用作是文件路径时,可以在提示项中提供自定义过滤器。

[Export(PropertyHint.File, "*.txt,")]
public string GameFile { get; set; }

也可以使用全局文件系统中的路径,仅工具模式下的脚本可以如此使用。

字符串还可以用作全局文件系统中某个 PNG 文件的路径。

[Export(PropertyHint.GlobalFile, "*.png")]
public string ToolImage { get; set; }

字符串也能用作全局文件系统中某个目录的路径。

[Export(PropertyHint.GlobalDir)]
public string ToolDir { get; set; }

多行文本注释会让编辑器使用大文本输入框来输入文本,而非那种小小的单行输入框。

[Export(PropertyHint.MultilineText)]
public string Text { get; set; }

编辑器内限制值的输入范围

使用范围属性提示允许你在编辑器中限制可以输入的值。

允许 0 到 20 之间的整数。

[Export(PropertyHint.Range, "0,20,")]
public int Number { get; set; }

允许 -10 到 20 之间的整数。

[Export(PropertyHint.Range, "-10,20,")]
public int Number { get; set; }

允许 -10 到 20 之间的数,调整步长为 0.2 。

[Export(PropertyHint.Range, "-10,20,0.2")]
public float Number { get; set; }

如果添加了 "or_greater" 和/或 "or_less" 的提示,在调整值时通过键入而非使用滑块,可以超过或低于限制。

[Export(PropertyHint.Range, "0,100,1,or_greater,or_less")]
public int Number { get; set; }

带缓动提示的浮点数

在编辑器里提供 'ease()' 函数的视觉呈现。

[Export(PropertyHint.ExpEasing)]
public float TransitionSpeed { get; set; }

颜色

使用红、绿、蓝、Alpha 值指定普通颜色。

[Export]
public Color Color { get; set; }

使用红、绿、蓝值指定颜色(此时Alpha 始终为 1)。

[Export(PropertyHint.ColorNoAlpha)]
public Color Color { get; set; }

节点

从 Godot 4.0 开始,节点可以直接导出,而不需要使用节点路径(NodePath)。

[Export]
public Node Node { get; set; }

A specific type of node can also be directly exported. The list of nodes shown after pressing "Assign" in the inspector is filtered to the specified type, and only a correct node can be assigned.

[Export]
public Sprite2D Sprite2D { get; set; }

Custom node classes can also be exported directly. The filtering behavior depends on whether the custom class is a global class.

如有需要,仍可以像 Godot 3.x 中那样导出 NodePath:

[Export]
public NodePath NodePath { get; set; }

public override void _Ready()
{
    var node = GetNode(NodePath);
}

资源

[Export]
public Resource Resource { get; set; }

在检查器里,可以将资源文件从文件系统面板中拖放到导出变量所对应的槽位中。

展开检查器下拉菜单可能导致一个极长的可能创建的类别列表。因此,如果你指定从 Resource 派生的类型的话:

[Export]
public AnimationNode AnimationNode { get; set; }

那么下拉菜单将只限于 AnimationNode 及其所有继承的类。也可以使用自定义的资源类,参见 C# 全局类

必须注意:即使在在编辑器模式中未运行脚本,导出的属性仍可编辑。这一点可以与 使用工具模式的脚本 配合使用。

导出位标记

具有 [Flags] 特性的枚举类型的成员可以被导出,它们的值被限制为枚举类型的成员。编辑器将在检查器中创建一个小部件,允许选择枚举成员中的零个、一个或多个。该值将被存储为整数。

A flags enum uses powers of 2 for the values of the enum members. Members that combine multiple flags using logical OR (|) are also possible.

[Flags]
public enum MyEnum
{
    Fire = 1 << 1,
    Water = 1 << 2,
    Earth = 1 << 3,
    Wind = 1 << 4,

    FireAndWater = Fire | Water,
}

[Export]
public SpellElements MySpellElements { get; set; }

Integers used as bit flags can store multiple true/false (boolean) values in one property. By using the Flags property hint, any of the given flags can be set from the editor.

[Export(PropertyHint.Flags, "Fire,Water,Earth,Wind")]
public int SpellElements { get; set; } = 0;

你必须为每个标志提供一个字符串描述。在这个例子中, Fire 的值是 1, Water 的值是 2, Earth 的值是 4, Wind 对应的值是 8。通常,应相应地定义常量(例如 private const int ElementWind = 8 等等)。

你可以使用冒号添加显式的值:

[Export(PropertyHint.Flags, "Self:4,Allies:8,Foes:16")]
public int SpellTargets { get; set; } = 0;

只有2的幂次方值才是有效的位标记选项。允许的最低值是1,因为0表示没有选中任何内容。你还可以添加一些其他标记的组合作为选项:

[Export(PropertyHint.Flags, "Self:4,Allies:8,Self and Allies:12,Foes:16")]
public int SpellTargets { get; set; } = 0;

也可以为项目设置中定义的物理层和渲染层提供导出提示。

[Export(PropertyHint.Layers2DPhysics)]
public uint Layers2DPhysics { get; set; }
[Export(PropertyHint.Layers2DRender)]
public uint Layers2DRender { get; set; }
[Export(PropertyHint.Layers3DPhysics)]
public uint Layers3DPhysics { get; set; }
[Export(PropertyHint.Layers3DRender)]
public uint Layers3DRender { get; set; }

使用位标记需要对位操作有一定的了解,若对此有疑问,请使用布尔变量代替位标记使用。

导出枚举

类型是枚举的成员可以导出,它们的值只能是枚举类型的成员之一。编辑器会在检查器中创建一个小部件,把以下内容列举为“Thing 1”、“Thing 2”、“Another Thing”。这个值会以整数的形式存储。

public enum MyEnum
{
    Thing1,
    Thing2,
    AnotherThing = -1,
}

[Export]
public MyEnum MyEnum { get; set; }

整数和字符串类型的成员也可以使用 [Export] 特性和 PropertyHint.Enum 提示来限制为特定的值列表。编辑器会在检查器中创建一个小部件,把以下内容列举为 Warrior、Magician、Thief。这个值会以整数的形式存储,对应于所选选项的索引(即 012 )。

[Export(PropertyHint.Enum, "Warrior,Magician,Thief")]
public int CharacterClass { get; set; };

你可以使用冒号添加显式的值:

[Export(PropertyHint.Enum, "Slow:30,Average:60,Very Fast:200")]
public int CharacterSpeed { get; set; }

如果类型是 string ,值将以字符串形式存储。

[Export(PropertyHint.Enum, "Rebecca,Mary,Leah")]
public string CharacterName { get; set; }

如果你想设置初始值,你必须明确指定它:

[Export(PropertyHint.Enum, "Rebecca,Mary,Leah")]
public string CharacterName { get; set; } = "Rebecca";

导出集合

C# Variant 文档所述,只有特定的 C# 数组和 Godot.Collections 命名空间中定义的集合类型是 Variant 兼容的,因此,只有这些类型才能被导出。

导出 Godot 数组

[Export]
public Godot.Collections.Array Array { get; set; }

Using the generic Godot.Collections.Array<T> allows specifying the type of the array elements, which will be used as a hint for the editor. The Inspector will restrict the elements to the specified type.

[Export]
public Godot.Collections.Array<string> Array { get; set; }

The default value of Godot arrays is null. A different default can be specified:

[Export]
public Godot.Collections.Array<string> CharacterNames { get; set; } = new Godot.Collections.Array<string>
{
    "Rebecca",
    "Mary",
    "Leah",
};

如果导出的数组指定了从 Resource 继承的类型,则可以一次性从文件系统面板中拖放多个文件到检查器中来设置该数组的值。

[Export]
public Godot.Collections.Array<Texture> Textures { get; set; }

[Export]
public Godot.Collections.Array<PackedScene> Scenes { get; set; }

导出 Godot 字典

[Export]
public Godot.Collections.Dictionary Dictionary { get; set; }

Using the generic Godot.Collections.Dictionary<TKey, TValue> allows specifying the types of the key and value elements of the dictionary.

备注

目前在 Godot 编辑器中不支持类型化字典,因此检查器将不会限制可以分配的类型,可能导致运行时异常。

[Export]
public Godot.Collections.Dictionary<string, int> Dictionary { get; set; }

The default value of Godot dictionaries is null. A different default can be specified:

[Export]
public Godot.Collections.Dictionary<string, int> CharacterLives { get; set; } = new Godot.Collections.Dictionary<string, int>
{
    ["Rebecca"] = 10,
    ["Mary"] = 42,
    ["Leah"] = 0,
};

导出 C# 数组

C# arrays can exported as long as the element type is a Variant-compatible type.

[Export]
public Vector3[] Vectors { get; set; }

[Export]
public NodePath[] NodePaths { get; set; }

The default value of C# arrays is null. A different default can be specified:

[Export]
public Vector3[] Vectors { get; set; } = new Vector3[]
{
    new Vector3(1, 2, 3),
    new Vector3(3, 2, 1),
}

从工具脚本中设置导出变量

工具模式 下的脚本中的一个导出变量的值改变时,该值在检查器中不会自动更新。要更新它,请在设置该导出变量的值之后调用 NotifyPropertyListChanged()

高级导出

为了避免非必要的复杂设计,并非所有类型的导出都在语言层面上提供。下面将说明一些能用底层 API 实现的,且较为常见的导出方法。

在进一步阅读前,你需要熟悉属性被处理的方式,以及它们是如何通过 _Set()_Get()_GetPropertyList() 等方法进行定制的。详情可参阅 从对象访问数据或逻辑

参见

要在 C++ 中用上述方法绑定属性,请参阅 使用 _set/_get/_get_property_list 绑定属性

警告

脚本必须在 tool 模式运行,才能使上述方法在编辑器内运行。