Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

序言

遊戲必須為其玩家提供清晰、資訊豐富且視覺上令人愉悅的使用者介面。雖然 Control 節點具有開箱即用的功能外觀,但始終有獨功能和特定於案例的調整空間。為此,Godot 引擎包括一個用於 GUI 換膚(或主題化)的系統,它允許您自訂使用者介面中每個控制項的外觀,包括您的自訂控制項。

下面是這個系統的一個例子—— 一個遊戲的 GUI 與引擎的預設 UI 主題完全不同:

../../_images/tank-kings-by-winterpixel-games.png

《坦克王》中的“裝備起來!”介面,由 Winterpixel Games 提供

除了為您的遊戲實作獨特的外觀外,該系統還使開發人員能夠為最終使用者提供自訂選項,包括互動設定。 UI 主題以級聯方式應用(即從父控制項傳播到其子控制項),這意味著色盲使用者的字形設定或調整,可以在從某處應用並影響整個 UI 樹。當然,這個系統也可以用於遊戲:基於英雄的遊戲可以為選定的玩家角色改變其風格,或者您可以為基於團隊的專案中的雙方賦予不同的風格。

主題基礎知識

皮膚系統由 Theme 資源驅動。每個 Godot 專案都有一個固有的預設主題,其中包含內建控制節點使用的設定。這就是使控制項具有開箱即用的獨特外觀的原因。然而,主題僅用於描述配置,並且每個單獨控制項的工作仍然是按照顯示自身所需的方式使用該配置。在實作 :ref:`你自己的自訂控制項 <doc_custom_gui_controls>`時要記住這一點很重要。

備註

甚至 Godot 編輯器本身也依賴於預設主題。但它看起來與 Godot 專案不同,因為它在預設主題之上應用了自己高度定制的主題。原則上,這與在您的遊戲中的工作方式完全相同,如下所述

主題

儲存在一個主題中的配置由主題專案組成。每個專案都有一個唯一的名稱,並且必須是以下資料型別之一:

  • 編輯器:

    color 值,通常用於字形和背景。顏色也可用於控制項和圖示的調變。

  • 常數

    整型值,可用於控制項的數位型別屬性(例如 BoxContainer 的間隙設定)或布林值標記(例如 Tree 中是否繪製關係線條)。

  • 霧:

    一個字形資源(font),常常被用於顯示控制項中的文字。字形包含了許多渲染設定,像字形的大小和顏色。之後呢,用另一個單獨的控制項來控制對齊屬性和文字方向。

  • 霧:

    一個整數值,與字形一起使用以確定文字的顯示大小。

  • 版本

    一個材質資源(texture),通常用於顯示一個圖示或者圖片(例如在按鈕中 Button)。

  • 樣式

    一個樣式盒資源(StyleBox),是一個用來定義一個UI面板怎樣展示的配置項集合。不只是用於面板控制項(Panel),它還常常用於許多控制項的背景設定和遮罩設定。

有名稱的型別

用來説明組織分配這些專案中每個主題該屬於哪些型別,並且每個專案只能屬於單個型別。也就是說,用命名來定義每個主題專案,它是資料型別也是它的主題型別。這些組合體中的主題必須是唯一的。例如,Label 型別中不能有 2 個叫做 font_color 的顏色專案,但是在另一個 LineEdit 中可以出現 font_color 專案。

Godot 的預設主題誕生之初就已經定義了眾多的主題型別,它內建於每個使用了 UI 皮膚的控制項節點中。在預設主題裡上述例子都是目前再用的主題專案。你可以在每個控制項的類參考手冊中查看**主題屬性**區域看看哪些專案是父類和子類別都可用的。

備註

子類別可以使用為其父類定義的主題項, Button 及其衍生型別就是很好實例。事實上,如果需要的話,每個控制項都可以使用任何主題型別的單個主題項,但為了清晰可控,在引擎中儘量避免這樣做。

牢記子類別中,哪些過程是自動執行的很重要.不論什麼時候內建控制項在主題裡面請求主題專案時,我們可以忽略主題型別僅通過它的類別名稱知悉。之後呢,下次時我們能根據它的父級類別名稱來使用.可以通過改變父級類,例如 Button,來影響所有衍生類,而不是調整每一個類來實作。

你當然可以定義你自己的主題型別,並且此外你還可以自訂所有內建控制項和自建控制項.因為內建控制項不會有你自訂主題的內容,所以你必須使用腳本把它們加入到這些專案中.所有控制項節點都有一系列的方法可以用來把目前應用主題的主題專案都例遍出來.這些方法通常是把主題型別做為一個可輸入參數.

var accent_color = get_theme_color("accent_color", "MyType")
label.add_color_override("font_color", accent_color)

為了提供更多的自訂可能性,型別還能夠連結在一起成為變種。這是自訂主題型別的另一種使用場景。例如,主題可以包含 Header 型別,標記為基礎 Label 型別的變種。那麼各個 Label 控制項就可以將其型別設為使用 Header 變種,主題請求主題專案的時候,這個變種都會先於其他型別使用。這樣就可以在同一個 Theme 資源裡為同樣使用某個類的控制項節點保存不同主題專案的預設值。

警告

只有預設主題或者自訂專案主題中的變種才會在“屬性面板”中列為可選項。在這兩處之外定義的變種名稱仍然可以手動輸入,但是建議把所有變種都放到專案主題裡面。

你可以通過:ref:`專門的文章 <doc_gui_theme_type_variations>`瞭解到更多關於主題型別變種的建立和使用的內容。

自訂控制項

可以不用主題直接對各個控制項節點進行自訂。這種方式稱為本地重載。控制項的類參考手冊中列出的每個主題屬性,無論是通過屬性面板面板還是腳本,都可以在該控制項上直接重載。這樣就可以針對 UI 中的特定部份進行精細的修改,不影響專案中包括該控制項子類別在內的其他內容。

../../_images/themecheck.png

本地重載對於提升使用者介面的美觀程度意義不大,如果你注重一致性的話就更是如此。然而,本地重載對於佈局節點而言是不可或缺的。BoxContainerGridContainer 等節點通過主題常數定義其子節點的間隙大小,MarginContainer 用主題專案來保存自訂邊距。

控制項存在本地主題專案重載時,會直接使用這個值,主題中所提供的值會被忽略。

建立專案

所有全新專案使用的都是 Godot 提供的預設專案主題。預設主題本身是常數,無法修改,但可以通過自訂主題進行覆蓋。設定自訂主題有兩種方法:修改專案設定,或者修改場景樹控制項節點的節點屬性。

目前有2個計畫設定適用於你的整個計畫專案 :gui/theme/custom 允許你設定一種自訂計畫專案寬屏主題,並且 gui/theme/custom_font 的功能和預設的字形是一樣的。當一個自訂主題的控制項節點使用一個主題專案時,如果專案存在它將被當先選中。只有當它不存在專案時,預設主題將被選中。

在一個單獨的主題資源中,你可以設定所有 Godot 控制項的預設樣式與外觀,但是你可以做更多的細節調整.每一個控制項節點同樣擁有一個:ref:`主題 <class_Control_property_theme>`屬性,通過這個屬性你可以為一個控制項的所有節點分支設定一個自訂的主題.那意味著那個控制項與其所有的子類別,和子類別的子類別,在回滾目前專案和預設主題之前自訂主題的資源將第一個被檢查。

備註

計畫設定作為一種變化的替代手段,可以讓你通過設定自訂主題資源對幾乎整個UI分支中的根控制項節點做出相同的影響. 然而運作計畫專案時可以充當預期效果展示,當單獨場景直接預覽或者運作時還將使用預設主題展示。為了解決這個問題你可以為每一個單獨場景中的根控制項設定相同的主題資源.

例如,你可以在專案主題中為按鈕設定特定的樣式,希望在彈出對話方塊中的按鈕又有不同的外觀。你可以為快顯視窗的根控制項設定自訂主題資源,並在該資源中為按鈕定義不同的樣式。只要快顯視窗的根控制項和按鈕之間的節點鏈不中斷,這些按鈕就會使用最接近它們的主題資源中定義的樣式。所有其他控制項仍將使用整個專案的主題和預設的主題樣式。

寶石計數器看起來應該長這樣

  1. 檢查相同資料型別和名稱的本地重寫。

  2. 使用控制項的類別名稱和父類別名稱:

    1. 從自身開始檢查每個控制項,看看它是否設定了主題屬性;

    2. 如果設定了,就在該主題中搜尋名稱、資料、主題型別都相同的專案;

    3. 如果沒有自訂主題,或者主題中沒有配對的條目,就前往父控制項;

    4. 重複步驟 a 至 c,到場景樹的根節點或者非控制項節點為止。

  3. 如果存在專案範圍的主題,就在這個主題中搜尋控制項的類別名稱。

  4. 在預設主題中搜尋控制項的類別名稱。

即便所有主題中都不存在對應的專案,也會返回一個針對該資料型別的預設值。

超越控制項

主題是一種用來保存視覺效果配置的理想資源,也非常合理。雖然其他節點並沒有像控制項節點一樣內建針對主題的支援,但還是可以和使用其他資源一樣來使用主題。

舉個非控制項使用主題的例子:在策略遊戲中,相同單位需要根據隊伍的不同而使用不同顏色的精靈。可以在主題資源中定義顏色的合集,精靈(在腳本的幫助下)就可以使用這些顏色來繪製紋理。這樣做的最大好處是可以為紅綠藍隊製作不同的主題但使用相同的主題專案,切換隊伍只需要替換資源就可以了。