GUI 換膚入門
遊戲必須為玩家提供清晰、資訊豐富且視覺上令人愉悅的使用者介面。雖然 Control 節點預設就有相當實用的外觀,但仍有不少空間可以讓你打造獨特的風格或進行針對性的調整。為此,Godot 引擎內建了 GUI 換膚(或主題)系統,讓你能自訂所有介面控制項的外觀,包括你自訂的控制項。
以下展示此系統的實際效果——一款遊戲的 GUI 與引擎預設的 UI 主題有著截然不同的風格:
《坦克王》中的「裝備起來!」介面,感謝 Winterpixel Games 授權提供
除了為遊戲打造獨特外觀外,這套系統也讓開發者能為終端使用者提供自訂選項,包括無障礙設定。UI 主題是以階層方式套用(也就是會從父控制項向下傳遞到子控制項),這代表像字型設定或色盲相關調整,都能在單一處設定並影響整個 UI 樹狀結構。當然,這套系統也能用於遊戲性設計:像英雄類遊戲可以讓選定角色有不同風格,或團隊遊戲可為不同勢力設計專屬樣式。
主題基礎
換膚系統是由 Theme 資源驅動。每個 Godot 專案都有一個內建的預設主題,包含所有內建控制項預設的外觀設定。這就是控制項預設外觀的來源。不過主題僅僅描述設定,實際如何運用這些設定來顯示,仍取決於各個控制項本身。這點在你實作 自訂控制項 時一定要注意。
備註
連 Godot 編輯器本身也依賴預設主題。但編輯器看起來和一般 Godot 專案不同,因為它在預設主題之上,疊加了高度自訂的主題。原則上這和你的遊戲專案的運作方式完全一樣,詳見 下方說明。
主題項目
儲存在主題中的設定由多個主題項目構成。每個項目都有唯一名稱,且必須屬於下列資料型別之一:
顏色
color 值,常用於字型和背景。顏色也可用於控制項和圖示的調色或變色。
常數
整數值,可用於控制項的數值屬性(例如 BoxContainer 的間距設定),或作為布林旗標(例如 Tree 是否繪製關聯線)。
字型
font 資源,供顯示文字的控制項使用。字型資源本身包含大部分文字算繪設定,但大小和顏色除外。對齊方式與文字方向則是由各控制項自訂。
字型大小
一個整數值,與字型一起決定文字顯示的大小。
圖示
StyleBox
StyleBox 資源,是一組定義 UI 面板顯示方式的設定集合。不只 Panel 控制項使用 StyleBox,許多控制項也都會用於其背景或覆蓋層。
不同控制項會以不同方式套用 StyleBox。特別的是,
focusStyleBox 會被繪製為其他 StyleBox(例如normal或pressed)的*覆蓋層*,以便基礎 StyleBox 仍可見。因此,focus StyleBox 應設計為描邊或半透明樣式,讓底層背景能被保留。
主題型別
為了方便組織管理,各主題會依型別區分,每個項目只能屬於一個型別。換句話說,每個主題項目都由名稱、資料型別與主題型別三者共同決定,這組合在同個主題內必須唯一。例如,Label 型別下不能有兩個叫 font_color 的顏色項目,但 LineEdit 型別下則可有另一個 font_color 項目。
Godot 的預設主題已經定義了多種主題型別,對應所有支援 UI 換膚的內建控制項節點。上面範例中提到的,就是預設主題實際存在的項目。你可以查閱各控制項的類別參考文件中的「主題屬性」章節,了解哪些項目可用於該類別及其子類別。
備註
子類別可以使用父類別定義的主題項目(例如 Button 及其衍生類別)。其實每個控制項理論上都能使用任何型別下的主題項目(但為了清晰性與可預測性,引擎實作上會盡量避免這樣做)。
要注意,對子類別來說這個流程是自動化的。當內建控制項向主題請求主題項目時,可以省略主題型別,會直接使用其類別名稱,接著也會依序查找其父類別名稱。這樣一來,像修改 Button 父類別的主題項目,就能影響所有衍生類別,而無須一一調整。
你也能自訂主題型別,進一步自訂內建控制項或你自己的控制項。不過,內建控制項不會自動識別你的自訂主題型別,因此你必須透過腳本來存取這些項目。所有控制項節點都有多種方法可從當前主題中取得主題項目,這些方法都能接受主題型別作為參數。
var accent_color = get_theme_color("accent_color", "MyType")
label.add_theme_color_override("font_color", accent_color)
Color accentColor = GetThemeColor("accent_color", "MyType");
label.AddThemeColorOverride("font_color", accentColor);
為了提供更多自訂彈性,型別之間也能設計成變種。這是自訂主題型別的另一個應用,例如主題中可以有個 Header 型別,標記為 Label 基礎型別的變種。個別 Label 控制項就可以指定型別為 Header,之後每次請求主題項目時,會優先使用這個變種。這樣就能在同一個 Theme 資源中,為同一類型的控制項儲存不同的主題項目預設值。
警告
只有預設主題或自訂專案主題中的變種,會在屬性檢視器裡顯示為可選項。你仍可手動輸入其他地方定義的變種名稱,但建議所有變種都統一放在專案主題中。
你可以參考 專門的文章,進一步了解主題型別變種的建立與應用。
自訂控制項
每個控制項節點都可以不透過主題而直接自訂,這稱為本地覆寫。你可以在屬性檢視器或用腳本,直接覆寫控制項類別參考中列出的每一個主題屬性。這能讓你細緻調整介面的某一部分,而不影響專案其他部分,包括這個控制項的子項。
本地覆寫對於整體 UI 美觀幫助有限,尤其當你追求一致性時更是如此。不過,對於排版用的節點來說則相當重要。像 BoxContainer 與 GridContainer 這類節點會用主題常數來定義子項間距;MarginContainer 則會將自訂邊界存於主題項目中。
當控制項有本地主題項目覆寫時,會優先使用這個值,主題所提供的值則會被忽略。
自訂專案
每個新專案預設都會採用 Godot 提供的預設專案主題。預設主題本身是固定的、無法修改,但你可以用自訂主題來覆寫它的項目。自訂主題有兩種套用方式:作為專案設定,或設定在控制項樹狀結構中的節點屬性。
有兩個專案設定可以影響整個專案:GUI > Theme > Custom 可設定全專案自訂主題,GUI > Theme > Custom Font 則用於設定預設備援字型。當控制項節點請求主題項目時,會先檢查自訂專案主題(若有設定),只有找不到時才會用預設主題。
這讓你可以用單一主題資源設定所有 Godot 控制項的預設外觀,但你也能做更細膩的調整。每個控制項節點也有 theme 屬性,能針對該節點及其所有子孫節點設定自訂主題。換句話說,這個控制項及其子孫節點會優先檢查這份自訂主題,找不到時才回退到專案主題及預設主題。
備註
你可以選擇不更動專案設定,而是將自訂主題資源設定到 UI 架構中最上層的控制項節點,效果幾乎相同。在專案執行時會如預期顯示,但如果你直接預覽或運行單一場景,則仍會套用預設主題。要解決這問題,可將同一份主題資源,也設定到各個場景的根控制項。
舉例來說,你可以在專案主題設定所有按鈕的統一風格,但希望彈跳視窗裡的按鈕是不同樣式。這時就可以將自訂主題資源設定到該快顯視窗的根控制項,並在主題中為按鈕定義另一種樣式。只要從快顯視窗的根控制項到按鈕之間的節點結構不中斷,這些按鈕就會使用最近的主題資源中定義的樣式。其餘控制項則仍然套用全專案主題與預設主題樣式。
總結來說,任一控制項查找主題項目的流程如下:
檢查是否有相同名稱與資料型別的本地覆寫。
依據控制項的型別變種、類別名稱與父類別名稱:
從自己開始,逐層往上檢查每個控制項是否有設定主題屬性;
如果有,則在該主題檢查有無同名、同型別、同主題型別的項目;
如果沒有自訂主題,或主題中沒有該項目,就往上檢查父控制項;
重複 a-c 步驟,直到場景樹根節點或遇到非控制項節點為止。
若有專案範圍主題,則依型別變種、類別名稱、父類別名稱查找該主題。
依型別變種、類別名稱、父類別名稱查找預設主題。
即使所有主題都找不到該項目,仍會回傳該資料型別的預設值。
控制項以外的應用
主題本身就是用來儲存視覺化設定的理想資源。雖然只有控制項節點內建支援主題,但其他節點也可以像使用其他資源一樣來引用主題。
主題也能應用在控制項以外的場景。例如策略遊戲中,相同單位在不同隊伍時需要不同的顏色顯示,就能用主題資源來定義一組顏色,並透過腳本讓精靈(Sprite)根據主題項目改變顏色繪製貼圖。這樣就能用同一組主題項目,製作紅隊、藍隊、綠隊等不同主題,僅需替換主題資源即可輕鬆切換。