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() 方法覆寫。
任何 Resource 或 Node 型別都可以匯出。屬性編輯器會針對這些型別顯示易於指定的對話框。這通常可以取代 GD.Load 和 GetNode。詳見 節點與資源。
[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; }
節點
自 Godot 4.0 起,節點可以直接匯出,無需再用 NodePath。
[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。該值會以整數儲存,對應所選項目的索引(即 0、1、2)。
[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; }
使用泛型 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> 可指定字典的鍵與值型別。
備註
目前 Godot 編輯器尚不支援型別化字典,因此 Inspector 不會限制可指定的型別,這可能導致執行時期例外。
[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 模式,上述方法才能於編輯器內運作。