Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

检查器插件

检查器面板支持以插件的形式来创建自定义小工具编辑属性。尽管可以用它来修改内置类型的检查器小工具,但它在需要处理自定义数据类型和资源时尤其有用。你不但可以为特定的属性或者整个对象设计自定义控件,还可以为特定数据类型设计单独的控件。

这份指南会介绍如何使用 EditorInspectorPluginEditorProperty 类来为整数类型创建自定义的界面,将默认的行为替换为一个按了以后就会生成 0 到 99 之间随机数的按钮。

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

左图为默认行为,右图为最终结果。

创建你的插件

从创建新的空插件开始。

参见

如何创建新插件请参阅 制作插件

让我们假设你的插件文件夹叫做 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)

与检查器交互

To interact with the inspector dock, your my_inspector_plugin.gd script must extend the EditorInspectorPlugin class. This class provides several virtual methods that affect how the inspector handles properties.

To have any effect at all, the script must implement the _can_handle() method. This function is called for each edited Object and must return true if this plugin should handle the object or its properties.

备注

要处理附加在该对象上的 Resource 也同样如此。

另外还有四个方法可以实现,用来往检查器的特定位置添加空间。parse_begin()parse_end() 方法顾名思义,只会在每个对象开始解析和结束解析的时候调用一次。在其中调用 add_custom_control() 就可以在检查器布局的顶部或底部添加控件。

As the editor parses the object, it calls the parse_category() and _parse_property() methods. There, in addition to add_custom_control(), you can call both add_property_editor() and add_property_editor_for_multiple_properties(). Use these last two methods to specifically add EditorProperty-based controls.

# 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, path, hint, hint_text, usage):
    # 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(path, 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. You should implement the _update_property() to handle changes to the data from the outside.

  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 后生成随机值。