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 提供了專屬的匯出語法。

只能對 Variant 相容型別 進行匯出。

備註

屬性也可以在 GDScript 中匯出,相關資訊請參閱 GDScript 匯出屬性

基本用法

匯出可以用於欄位與屬性,且存取修飾詞不限。

[Export]
private int _number;

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

匯出的成員可以指定預設值;若未指定,則會採用 型別的預設值

Number 這樣的 int 預設值為 0。而 Text 預設為 null,因為 string 屬於參考型別。

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

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

欄位與屬性皆可指定預設值。

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

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

有備援欄位的屬性會使用備援欄位的預設值。

private int _number = 2;

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

備註

屬性的 get 方法實際上並不會執行來決定預設值。Godot 會直接分析 C# 原始碼。這在大多數情況下都沒問題,但有些屬性若過於複雜,分析器可能無法正確判斷。

例如,下列屬性嘗試用數學運算讓屬性編輯器顯示預設值 5,但這樣並不會如預期運作:

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

private int _number = 2;

分析器無法解析這段程式碼,因此會回退為 int 的預設值 0。但執行場景或檢查有 tool script 的節點時,_number 會是 2,而 NumberWithBackingField 會回傳 5。這樣的落差可能導致行為混淆。為避免這種情況,請避免用複雜屬性。如果可以明確指定預設值,也可用 _PropertyCanRevert()_PropertyGetRevert() 方法覆寫。

任何 ResourceNode 型別都可以匯出。屬性編輯器會針對這些型別顯示易於指定的對話框。這通常可以取代 GD.LoadGetNode。詳見 節點與資源

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

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

匯出屬性分組

可以在屬性編輯器(Inspector)中,透過 [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; }

multiline 註記會讓編輯器顯示較大的欄位以編輯多行文字。

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

限制編輯器輸入範圍

使用 range 屬性提示可以限制在編輯器中可輸入的值。

允許 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; }

匯出時加上單位提示

為匯出的變數顯示單位提示。適用於數值型別,如浮點數或向量:

[Export(PropertyHint.None, "suffix:m/s\u00b2")]
public float Gravity { get; set; } = 9.8f;
[Export(PropertyHint.None, "suffix:m/s")]
public Vector3 Velocity { get; set; }

在上述範例中,\u00b2 用來顯示「平方」符號(²)。

顏色

以紅、綠、藍、Alpha 值指定的標準顏色。

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

以紅、綠、藍值指定顏色(Alpha 固定為 1)。

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

節點

Nodes can also be directly exported without having to use NodePaths.

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

也可以直接匯出特定型別的節點。在屬性檢視器按下「指派」後,顯示的節點列表會依指定型別過濾,只能指派符合型別的節點。

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

自訂節點類別也能直接匯出。過濾行為取決於自訂類別是否為 全域類別

如有需要,仍可如 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# 全域類別

請注意,即使腳本在編輯器中未執行,匯出屬性仍可編輯。這可以搭配 「tool」模式腳本 使用。

匯出位元旗標

型別為帶有 [Flags] 屬性的列舉成員可以匯出,其值僅限於該列舉型別的成員。編輯器會在屬性檢視器建立即時元件,讓你可以選擇不選、單選或多選列舉成員。該值會以整數存儲。

列舉型別帶有 [Flags] 屬性時,成員值通常為 2 的冪次方。也可以用邏輯 OR(|)組合多個旗標成一個成員。

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

    FireAndWater = Fire | Water,
}

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

以整數作為位元旗標時,可以在單一屬性內儲存多個 true / false``(布林)值。透過 ``Flags 屬性提示,可在編輯器中勾選任意旗標。

[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; }

使用位元旗標需要基本的位元運算知識。如不熟悉,請改用布林變數。

匯出列舉(Enum)

型別為列舉的成員可以匯出,其值僅限於列舉型別的成員。編輯器會在屬性檢視器產生元件,將下列選項列舉為「Thing 1」、「Thing 2」、「Another Thing」。該值會以整數儲存。

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

[Export]
public MyEnum MyEnumCurrent { 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";

匯出 Inspector 按鈕(使用 [ExportToolButton]

如需在 Inspector 建立可點擊的按鈕,可使用 [ExportToolButton] 屬性。這會將一個 Callable 屬性或欄位匯出成可點擊按鈕。由於這會在編輯器執行,因此必須加上 [Tool] 屬性。按下按鈕時,對應的 callable 會被呼叫:

[Tool]
public partial class MyNode : Node
{
    [ExportToolButton("Click me!")]
    public Callable ClickMeButton => Callable.From(ClickMe);

    public void ClickMe()
    {
        GD.Print("Hello world!");
    }
}

你也可以用第二個參數為按鈕指定圖示。若有指定,會透過 GetThemeIcon()"EditorIcons" 主題中取得圖示。

[ExportToolButton("Click me!", Icon = "CharacterBody2D")]
public Callable ClickMeButton => Callable.From(ClickMe);

匯出集合

C# Variant 文件所述,僅有部分 C# 陣列與 Godot.Collections 命名空間中定義的集合型別與 Variant 相容,因此只有這些型別可匯出。

匯出 Godot 陣列

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

使用泛型 Godot.Collections.Array<T> 可指定陣列元素型別,編輯器會以此作為提示,Inspector 也會限制元素型別。

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

Godot 陣列的預設值為 null,可指定不同預設值:

[Export]
public Godot.Collections.Array<string> CharacterNames { get; set; } =
[
    "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; }

使用泛型 Godot.Collections.Dictionary<TKey, TValue> 可指定字典的鍵與值型別。

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

Godot 字典的預設值為 null,可指定不同預設值:

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

匯出 C# 陣列

只要元素型別是 Variant 相容型別,C# 陣列就可以匯出。

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

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

C# 陣列的預設值為 null,可指定不同預設值:

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

從 tool 腳本設定匯出變數

工具模式 腳本中修改匯出變數值時,Inspector 上顯示的值不會自動更新。如要更新,請在設定匯出變數值後呼叫 NotifyPropertyListChanged()

進階匯出

為避免語言設計過於複雜,並非所有匯出型別都能直接由語言層級提供。以下介紹一些常見但需使用低階 API 實現的匯出功能。

在深入閱讀之前,建議先熟悉屬性處理方式,以及如何透過 _Set()_Get()_GetPropertyList() 方法來自訂屬性,詳見 從物件中存取資料或邏輯

也參考

如需在 C++ 中使用上述方法綁定屬性,請參閱 用 _set/_get/_get_property_list 綁定屬性

警告

腳本必須運作於 tool 模式,上述方法才能於編輯器內運作。