制作插件

关于插件

A plugin is a great way to extend the editor with useful tools. It can be made entirely with GDScript and standard scenes, without even reloading the editor. Unlike modules, you don't need to create C++ code nor recompile the engine. While this makes plugins less powerful, there are still many things you can do with them. Note that a plugin is similar to any scene you can already make, except it is created using a script to add editor functionality.

这个教程会教您写两个简单的插件来帮助您理解插件如何运作和如何写插件。首先是一个可以往任何场景添加的自定义节点,其次呢,是个可以往编辑器里添加的自定义面板。

创建一个插件

在开始前,先找个地方创建个空项目。这个空项目是制作和测试我们插件的基础。

编辑器要识别一个新的插件,首先需要创建两个文件:一个是``plugin.cfg``用于配置和具有此功能的工具脚本。插件在项目文件夹里面有一个标准路径,比如``addons/plugin_name``。Godot提供了一个属性框,用于生成这些文件并将它们放在需要的位置。

在主工具栏中,点击``Project``[项目]下拉菜单,然后点击``Project Settings...``[项目设置].然后转到``Plugins``[插件]选项卡,在点击右上角的``Create``[创建]按钮。

你将看到属性面板出现,如下所示:

../../../_images/making_plugins-create_plugin_dialog.png

每个字段中文本属性都描述了它会影响到哪些配置文件的值。

如果要继续使用该例子,请使用下列的值:

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

你最终的目录结构应该是这样显示的:

../../../_images/making_plugins-my_custom_mode_folder.png

plugin.cfg is a simple INI file with metadata about your plugin. The name and description help people understand what it does. Your name helps you get properly credited for your work. The version number helps others know if they have an outdated version; if you are unsure on how to come up with the version number, check out Semantic Versioning. The main script file will instruct Godot what your plugin does in the editor once it is active.

脚本文件

创建插件后,对话框会自动为你打开EditorPlugin脚本。该脚本有两个要求,你不能改变:它必须是一个 tool 脚本,否则将无法在编辑器中正常加载;它必须继承 EditorPlugin

警告

除了EditorPlugin脚本之外,插件所使用的任何其他GDScript也必须是一个tool。 任何没有 tool 导入编辑器的GDScript都会像一个空文件一样!

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
#if TOOLS
using Godot;
using System;

[Tool]
public class CustomNode : EditorPlugin
{
    public override void _EnterTree()
    {
        // Initialization of the plugin goes here.
    }

    public override void _ExitTree()
    {
        // Clean-up of the plugin goes here.
    }
}
#endif

这是创建新插件时使用的好模板。

自定义节点

有时您希望在许多节点中存在某种行为,例如可以重复使用的自定义场景或控件。 实例化在很多情况下都很有用,但有时它会很麻烦,特别是如果您在许多项目中使用它。 一个很好的解决方案是创建一个插件,添加一个具有自定义行为的节点。

警告

通过EditorPlugin添加的节点是 "CustomType "节点。虽然它们可以与任何脚本语言一起工作,但功能比 脚本类系统 少。如果你正在编写GDScript或NativeScript,建议使用脚本类代替。

To create a new node type, you can use the function add_custom_type() from the EditorPlugin class. This function can add new types to the editor (nodes or resources). However, before you can create the type, you need a script that will act as the logic for the type. While that script doesn't have to use the tool keyword, it can be added so the script runs in the editor.

For this tutorial, we'll create a simple button that prints a message when clicked. For that, we'll need a simple script that extends from Button. It could also extend BaseButton if you prefer:

tool
extends Button


func _enter_tree():
    connect("pressed", self, "clicked")


func clicked():
    print("You clicked me!")
using Godot;
using System;

[Tool]
public class MyButton : Button
{
    public override void _EnterTree()
    {
        Connect("pressed", this, "clicked");
    }

    public void clicked()
    {
        GD.Print("You clicked me!");
    }
}

That's it for our basic button. You can save this as my_button.gd inside the plugin folder. You'll also need a 16×16 icon to show in the scene tree. If you don't have one, you can grab the default one from the engine and save it in your addons/my_custom_node folder as icon.png, or use the default Godot logo (preload("res://icon.png")). You can also use SVG icons if desired.

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

Now, we need to add it as a custom type so it shows on the Create New Node dialog. For that, change the custom_node.gd script to the following:

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")
#if TOOLS
using Godot;
using System;

[Tool]
public class CustomNode : EditorPlugin
{
    public override void _EnterTree()
    {
        // Initialization of the plugin goes here.
        // Add the new type with a name, a parent type, a script and an icon.
        var script = GD.Load<Script>("MyButton.cs");
        var texture = GD.Load<Texture>("icon.png");
        AddCustomType("MyButton", "Button", script, texture);
    }

    public override void _ExitTree()
    {
        // Clean-up of the plugin goes here.
        // Always remember to remove it from the engine when deactivated.
        RemoveCustomType("MyButton");
    }
}
#endif

完成后,插件应该已经在 项目设置 的插件列表中可用,因此请按照 Checking the results 中的说明激活它。

然后通过添加新节点来尝试:

../../../_images/making_plugins-custom_node_create.png

When you add the node, you can see that it already has the script you created attached to it. Set a text to the button, save and run the scene. When you click the button, you can see some text in the console:

../../../_images/making_plugins-custom_node_console.png

自定义窗口

有时,您需要扩展编辑器并添加始终可用的工具。 一种简单的方法是添加一个带插件的新扩展面板。 Docks只是基于Control的场景,因此它们的创建方式与通常的GUI场景类似。

Creating a custom dock is done just like a custom node. Create a new plugin.cfg file in the addons/my_custom_dock folder, then add the following content to it:

[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"
[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="CustomDock.cs"

然后在同一文件夹中创建脚本 custom_dock.gd 。 使用 template we've seen before 填充它以获得良好的开端。

由于我们正在尝试添加新的自定义窗口,因此我们需要创建窗口的内容。 这只不过是一个标准的Godot场景:只需在编辑器中创建一个新场景然后编辑它。

对于编辑器停靠站,根节点 必须是 Control 或其子类之一。 在本教程中,您可以创建一个按钮。 根节点的名称也将是面板对话框中显示的名称,因此请务必为其指定一个简短的描述性名称。 另外,不要忘记在按钮上添加一些文字。

../../../_images/making_plugins-my_custom_dock_scene.png

Save this scene as my_dock.tscn. Now, we need to grab the scene we created then add it as a dock in the editor. For this, you can rely on the function add_control_to_dock() from the EditorPlugin class.

You need to select a dock position and define the control to add (which is the scene you just created). Don't forget to remove the dock when the plugin is deactivated. The script could look like this:

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 instance it.
    dock = preload("res://addons/my_custom_dock/my_dock.tscn").instance()

    # 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()
#if TOOLS
using Godot;
using System;

[Tool]
public class CustomDock : EditorPlugin
{
    Control dock;

    public override void _EnterTree()
    {
        dock = (Control)GD.Load<PackedScene>("addons/my_custom_dock/my_dock.tscn").Instance();
        AddControlToDock(DockSlot.LeftUl, dock);
    }

    public override void _ExitTree()
    {
        // Clean-up of the plugin goes here.
        // Remove the dock.
        RemoveControlFromDocks(dock);
        // Erase the control from the memory.
        dock.Free();
    }
}
#endif

Note that, while the dock will initially appear at its specified position, the user can freely change its position and save the resulting layout.

检查结果

现在是检查工作结果的时候了。 打开 项目设置 ,然后单击 插件 选项卡。 您的插件应该是列表中唯一的插件。 如果未显示,请单击右上角的 更新 按钮。

../../../_images/making_plugins-project_settings.png

您可以在 Status 列中看到该插件处于非激活状态; 点击状态选择 Active 。 在您关闭设置窗口之前,该扩展窗口应该可见。 您现在应该看到一个自定义窗口:

../../../_images/making_plugins-custom_dock.png

举一反三

现在您已经学会了如何制作基本插件,您可以通过多种方式扩展编辑器。 可以使用GDScript将许多功能添加到编辑器中; 它是一种创建专业编辑器的强大方法,无需深入研究C++模块。

您可以制作自己的插件来帮助自己或在 资源馆 中分享它们,以便人们可以从您的工作中受益。