Up to date

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

屬性面板外掛程式

屬性面板面板支援以外掛程式的形式來建立自訂小工具編輯屬性。儘管可以用它來修改內建型別的屬性面板小工具,但它在需要處理自訂資料型別和資源時尤其有用。你不但可以為特定的屬性或者整個物件設計自訂控制項,還可以為特定資料型別設計單獨的控制項。

這份指南會介紹如何使用 EditorInspectorPluginEditorProperty 類來為整數型別建立自訂的介面,將預設的行為替換為一個按了以後就會生成 0 到 99 之間亂數的按鈕。

../../../_images/inspector_plugin_example.png

左圖為預設行為,右圖為最終結果。

設定 Python

從建立新的空外掛程式開始。

也參考

如何建立新外掛程式請參閱 製作外掛程式

讓我們假設你的外掛程式資料夾叫做 my_inspector_plugin。那麼此時你新建的 addons/my_inspector_plugin 資料夾中就有兩個檔案:plugin.cfgplugin.gd

和之前一樣,plugin.gd 是一個擴充了 EditorPlugin 的腳本,你需要在 _enter_tree_exit_tree 方法中加入新的程式碼。要建立自己的屬性面板外掛程式,你必須載入對應的腳本,然後建立並呼叫 add_inspector_plugin() 來新增實例。禁用外掛程式時,你應該呼叫 remove_inspector_plugin() 將該實例移除。

備註

因為你在這裡讀取的是腳本而不是場景包,所以應該使用 new() 而不是 instance()

# plugin.gd
@tool
extends EditorPlugin

var plugin


func _enter_tree():
    plugin = preload("res://addons/my_inspector_plugin/my_inspector_plugin.gd").new()
    add_inspector_plugin(plugin)


func _exit_tree():
    remove_inspector_plugin(plugin)

產生金鑰儲存區

要和屬性面板面板互動,你的 my_inspector_plugin.gd 腳本必須繼承自 EditorInspectorPlugin 類。這個類提供了不少虛方法,可以用來控制屬性面板對屬性的處理。

腳本必須實作 can_handle() 方法才能生效。這個函式會針對每個被編輯的 Object 物件呼叫,外掛程式想要處理該物件或其屬性的話,就必須返回 true

備註

要處理附加在該物件上的 Resource 也同樣如此。

另外還有四個方法可以實作,用來往屬性面板的特定位置新增空間。parse_begin()parse_end() 方法顧名思義,只會在每個物件開始解析和結束解析的時候呼叫一次。在其中呼叫 add_custom_control() 就可以在屬性面板佈局的頂部或底部新增控制項。

編輯器解析物件時,會呼叫 parse_category()_parse_property() 方法。在這兩個函式中,除了 add_custom_control() 以外,你還可以呼叫 add_property_editor()add_property_editor_for_multiple_properties(),這兩個函式是專門用來新增基於 EditorProperty 的控制項的。

# my_inspector_plugin.gd
extends EditorInspectorPlugin

var RandomIntEditor = preload("res://addons/my_inspector_plugin/random_int_editor.gd")


func _can_handle(object):
    # We support all objects in this example.
    return true


func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):
    # We handle properties of type integer.
    if type == TYPE_INT:
        # Create an instance of the custom property editor and register
        # it to a specific property path.
        add_property_editor(name, RandomIntEditor.new())
        # Inform the editor to remove the default property editor for
        # this property type.
        return true
    else:
        return false

新增檔案至專案

EditorProperty 是一種特殊的 Control,可以與屬性面板面板所編輯的物件進行互動。它本身不顯示任何內容,但可以放入其他控制項節點,甚至是複雜的場景。

擴充 EditorProperty 的腳本有三個必不可少的部分:

  1. 必須定義 _init() 方法,設定控制項節點的結構。

  2. 應該實作 _update_property(),處理外部對資料的更改。

  3. 必須在某處使用 emit_changed 觸發訊號,告知屬性面板本控制項對屬性進行了修改。

顯示自訂小工具的方法有兩種。可以只用預設的 add_child() 方法可以把它顯示到屬性名稱的右邊,在 add_child() 之後再呼叫 set_bottom_editor() 就可以把它顯示到名稱的下邊。

# random_int_editor.gd
extends EditorProperty


# The main control for editing the property.
var property_control = Button.new()
# An internal value of the property.
var current_value = 0
# A guard against internal changes when the property is updated.
var updating = false


func _init():
    # Add the control as a direct child of EditorProperty node.
    add_child(property_control)
    # Make sure the control is able to retain the focus.
    add_focusable(property_control)
    # Setup the initial state and connect to the signal to track changes.
    refresh_control_text()
    property_control.pressed.connect(_on_button_pressed)


func _on_button_pressed():
    # Ignore the signal if the property is currently being updated.
    if (updating):
        return

    # Generate a new random integer between 0 and 99.
    current_value = randi() % 100
    refresh_control_text()
    emit_changed(get_edited_property(), current_value)


func _update_property():
    # Read the current value from the property.
    var new_value = get_edited_object()[get_edited_property()]
    if (new_value == current_value):
        return

    # Update the control with the new value.
    updating = true
    current_value = new_value
    refresh_control_text()
    updating = false

func refresh_control_text():
    property_control.text = "Value: " + str(current_value)

使用上面的範例程式碼,可以實作用自訂的小工具替代整數預設的 SpinBox 控制項,點擊 Button 後生成隨機值。