Up to date

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

製作外掛程式

關於外掛程式

外掛程式是用有用的工具來擴充編輯器的一個好方法. 它可以完全用GDScript和標準場景製作, 甚至不需要重新載入編輯器. 與模組不同, 你不需要建立C++程式碼也不需要重新編譯引擎. 雖然這使得外掛程式的功能不那麼強大, 但你仍然可以用它們做很多事情. 請注意, 一個外掛程式與你已經可以製作的任何場景相似, 只是它是用腳本建立的, 以增加編輯器功能.

這個教學會教您寫兩個簡單的外掛程式來幫助您理解外掛程式如何運作和如何寫外掛程式. 首先是一個可以往任何場景新增的自訂節點, 其次呢, 是個可以往編輯器裡新增的自訂面板.

建立外掛程式

在開始前, 先找個地方建立個空專案. 這個空專案是製作和測試我們外掛程式的基礎.

編輯器要識別一個新的外掛程式, 首先需要建立兩個檔: 一個是 plugin.cfg 用於配置和具有此功能的工具腳本. 外掛程式在專案檔案夾裡面有一個標準路徑, 比如 addons/plugin_name.Godot提供了一個屬性框, 用於生成這些檔並將它們放在需要的位置.

在主工具列中,點擊 專案 下拉式功能表,然後點擊 專案設定...。然後轉到 外掛程式 分頁,點擊右上角的 建立 按鈕。

你會看到出現了一個對話方塊,類似這樣:

../../../_images/making_plugins-create_plugin_dialog.webp

每個欄位中文字屬性都描述了它會影響到哪些設定檔的值.

有下列事項需注意:

Plugin Name: My Custom Node
Subfolder: my_custom_node
Description: A custom node made to extend the Godot Engine.
Author: Your Name Here
Version: 1.0.0
Language: GDScript
Script Name: custom_node.gd
Activate now: No

警告

始終需要在 C# 中去掉對 立即啟動? 選項的勾選,因為和其他 C# 腳本一樣,EditorPlugin 腳本是需要編譯的,要求建構整個專案。建構專案後,就可以在 專案設定外掛程式 分頁中啟用該外掛程式。

你最終的目錄結構應該是這樣顯示的:

../../../_images/making_plugins-my_custom_mode_folder.webp

plugin.cfg 是一個簡單的INI檔, 包含關於你的外掛程式的中繼資料. 名稱和描述有助於人們瞭解它的作用. 你的名字有助於你的工作得到正確的認可. 版本號可以幫助別人知道他們是否有一個過時的版本;如果你不確定如何得出版本號, 請查看 Semantic Versioning . 主指令檔將指示Godot, 一旦你的外掛程式被啟動後, 它將在編輯器中做什麼.

指令檔

建立外掛程式後, 對話方塊會自動為你打開EditorPlugin腳本. 該腳本有兩個要求, 你不能改變: 它必須是一個 @tool 腳本, 否則將無法在編輯器中正常載入;它必須繼承 EditorPlugin.

警告

除了 EditorPlugin 腳本之外,外掛程式用到的其他 GDScript *也*必須是工具腳本。*沒有 @tool 的 GDScript 在匯入編輯器後都會像空檔一樣!*建構專案時不會重新載入沒有 [Tool] 的 C# 類,你就只能重新啟用外掛程式了!

It's important to deal with initialization and clean-up of resources. A good practice is to use the virtual function _enter_tree() to initialize your plugin and _exit_tree() to clean it up. Thankfully, the dialog generates these callbacks for you. Your script should look something like this:

@tool
extends EditorPlugin


func _enter_tree():
    # Initialization of the plugin goes here.
    pass


func _exit_tree():
    # Clean-up of the plugin goes here.
    pass

這是建立新外掛程式時使用的好範本.

自訂節點

有時您希望在許多節點中存在某種行為, 例如可以重複使用的自訂場景或控制項. 產生實體在很多情況下都很有用, 但有時它會很麻煩, 特別是如果您在許多專案中使用它. 一個很好的解決方案是建立一個外掛程式, 新增一個具有自訂行為的節點.

警告

通過 EditorPlugin 新增的節點是“CustomType”(自訂型別)節點。雖然它們可以用於任何指令碼語言,但功能比 :ref:`Script 類系統 <doc_gdscript_basics_class_name>`少。如果你正在編寫 GDScript 或 NativeScript,建議使用 Script 類代替。

要建立一個新的節點型別, 你可以使用來自 EditorPlugin 類的 add_custom_type() 這個函式. 這個函式可以向編輯器新增新的型別(節點或資源). 但是, 在你建立型別之前, 需要一個腳本, 作為型別的邏輯. 雖然該腳本不一定要使用 @tool 關鍵字, 但可以新增它, 以便腳本在編輯器中運作.

在本教學中, 我們將建立一個簡單的按鈕, 在點擊時列印出一條資訊. 對此, 我們需要一個從 Button 擴充的簡單腳本. 如果你願意, 它也可以擴充 BaseButton :

@tool
extends Button


func _enter_tree():
    pressed.connect(clicked)


func clicked():
    print("You clicked me!")

這就是我們的基本按鈕了. 你可以把它保存為外掛程式資料夾中的 my_button.gd . 你還需要一個16×16的圖示來顯示在場景樹中. 如果你沒有, 可以從引擎中抓取預設的, 並保存在你的 addons/my_custom_node 資料夾中, 作為 icon.png , 或者使用預設的Godot旗標( preload("res://icon.png") ). 如果需要, 你也可以使用SVG圖示.

../../../_images/making_plugins-custom_node_icon.png

現在,我們需要把它作為一個自訂型別新增,以便它顯示在**新建 Node** 的對話方塊中。為此,將 custom_node.gd 腳本改為以下內容:

@tool
extends EditorPlugin


func _enter_tree():
    # Initialization of the plugin goes here.
    # Add the new type with a name, a parent type, a script and an icon.
    add_custom_type("MyButton", "Button", preload("my_button.gd"), preload("icon.png"))


func _exit_tree():
    # Clean-up of the plugin goes here.
    # Always remember to remove it from the engine when deactivated.
    remove_custom_type("MyButton")

完成後, 外掛程式應該已經在 專案設定 的外掛程式列表中可用, 因此請按照 Checking the results 中的說明啟動它.

然後通過新增新節點來嘗試:

../../../_images/making_plugins-custom_node_create.webp

當你新增節點時, 你可以看到它已經有你建立的腳本附加在上面. 給這個按鈕設定一個文字, 保存並運作場景. 當你點擊按鈕時, 你可以在控制台中看到一些文字:

../../../_images/making_plugins-custom_node_console.webp

自訂視窗

有時, 您需要擴充編輯器並新增始終可用的工具. 一種簡單的方法是新增一個帶外掛程式的新擴充面板. Docks只是基於Control的場景, 因此它們的建立方式與通常的GUI場景類似.

建立一個自訂欄好的方法和自訂節點一樣. 在 addons/my_custom_dock 資料夾中建立一個新的 plugin.cfg 檔, 然後在其中新增以下內容:

[plugin]

name="My Custom Dock"
description="A custom dock made so I can learn how to make plugins."
author="Your Name Here"
version="1.0"
script="custom_dock.gd"

然後在同一資料夾中建立腳本 custom_dock.gd。填寫:ref:`之前見過的範本 <doc_making_plugins_template_code>`以獲得良好的開端。

由於我們正在嘗試新增新的自訂視窗, 因此我們需要建立視窗的內容. 這只不過是一個標準的Godot場景: 只需在編輯器中建立一個新場景然後編輯它.

對於編輯器停靠站, 根節點 必須是 Control 或其子類別之一. 在本教學中, 您可以建立一個按鈕. 根節點的名稱也將是面板對話方塊中顯示的名稱, 因此請務必為其指定一個簡短的描述性名稱. 另外, 不要忘記在按鈕上新增一些文字.

../../../_images/making_plugins-my_custom_dock_scene.webp

把這個場景保存為 my_dock.tscn . 現在, 我們需要抓取我們建立的場景, 然後在編輯器中把它新增為一個欄目. 為此, 你可以依賴 add_control_to_dock() 這個函式, 它來自 EditorPlugin 類.

你需要選擇一個停靠位置並定義要新增的控制項, 也就是你剛剛建立的場景. 不要忘了在外掛程式停用時 remove the dock . 腳本可以是這樣的:

@tool
extends EditorPlugin


# A class member to hold the dock during the plugin life cycle.
var dock


func _enter_tree():
    # Initialization of the plugin goes here.
    # Load the dock scene and instantiate it.
    dock = preload("res://addons/my_custom_dock/my_dock.tscn").instantiate()

    # Add the loaded scene to the docks.
    add_control_to_dock(DOCK_SLOT_LEFT_UL, dock)
    # Note that LEFT_UL means the left of the editor, upper-left dock.


func _exit_tree():
    # Clean-up of the plugin goes here.
    # Remove the dock.
    remove_control_from_docks(dock)
    # Erase the control from the memory.
    dock.free()

請注意, 雖然Dock最初會出現在其指定的位置, 但使用者可以自由改變其位置, 並保存所產生的佈局.

檢查結果

現在是檢查工作結果的時候了. 打開 專案設定 , 然後按一下 外掛程式 分頁. 您的外掛程式應該是列表中唯一的外掛程式. 如果未顯示, 請按一下右上角的 更新 按鈕.

../../../_images/making_plugins-project_settings.webp

您可以在 Status 列中看到該外掛程式處於非啟動狀態; 點擊狀態選擇 Active . 在您關閉設定視窗之前, 該擴充視窗應該可見. 您現在應該看到一個自訂視窗:

../../../_images/making_plugins-custom_dock.webp

舉一反三

現在您已經學會了如何製作基本外掛程式, 您可以通過多種方式擴充編輯器. 可以使用GDScript將許多功能新增到編輯器中; 它是一種建立專業編輯器的強大方法, 無需深入研究C++模組.

您可以製作自己的外掛程式來幫助自己或在 素材庫 中分享它們,以便人們可以從您的工作中受益。

在外掛程式中註冊自動載入/單例

編輯器外掛程式可以在啟用時自動註冊:ref:自動載入 <doc_singletons_autoload>。同樣也包含了在外掛程式禁用時反註冊該自動載入。

這樣使用者就可以更快速地設定外掛程式了,因為你的編輯器外掛程式要求使用自動載入時,他們不必再手動去專案設定裡新增自動載入了。

可以使用下列指令來移除產生的匯出樣板:

@tool
extends EditorPlugin

# Replace this value with a PascalCase autoload name, as per the GDScript style guide.
const AUTOLOAD_NAME = "SomeAutoload"


func _enter_tree():
    # The autoload can be a scene or script file.
    add_autoload_singleton(AUTOLOAD_NAME, "res://addons/my_addon/some_autoload.tscn")


func _exit_tree():
    remove_autoload_singleton(AUTOLOAD_NAME)