制作插件
关于插件
插件是用有用的工具来扩展编辑器的一个好方法. 它可以完全用GDScript和标准场景制作, 甚至不需要重新加载编辑器. 与模块不同, 你不需要创建C++代码也不需要重新编译引擎. 虽然这使得插件的功能不那么强大, 但你仍然可以用它们做很多事情. 请注意, 一个插件与你已经可以制作的任何场景相似, 只是它是用脚本创建的, 以增加编辑器功能.
这个教程会教您写两个简单的插件来帮助您理解插件如何运作和如何写插件. 首先是一个可以往任何场景添加的自定义节点, 其次呢, 是个可以往编辑器里添加的自定义面板.
创建插件
在开始前, 先找个地方创建个空项目. 这个空项目是制作和测试我们插件的基础.
编辑器要识别一个新的插件, 首先需要创建两个文件: 一个是 plugin.cfg
用于配置和具有此功能的工具脚本. 插件在项目文件夹里面有一个标准路径, 比如 addons/plugin_name
.Godot提供了一个属性框, 用于生成这些文件并将它们放在需要的位置.
在主工具栏中,点击 项目
下拉菜单,然后点击 项目设置...
。然后转到 插件
选项卡,点击右上角的 创建
按钮。
你会看到出现了一个对话框,类似这样:
每个字段中文本属性都描述了它会影响到哪些配置文件的值.
To continue with the example, use the following values:
GDScriptC#
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
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: C#
Script Name: CustomNode.cs
Activate now: No
警告
Unchecking the Activate now?
option in C# is always required because, like every other C# script, the EditorPlugin script needs to be compiled which requires building the project. After building the project the plugin can be enabled in the Plugins
tab of Project Settings
.
你最终的目录结构应该是这样显示的:
plugin.cfg
是一个简单的INI文件, 包含关于你的插件的元数据. 名称和描述有助于人们了解它的作用. 你的名字有助于你的工作得到正确的认可. 版本号可以帮助别人知道他们是否有一个过时的版本;如果你不确定如何得出版本号, 请查看 Semantic Versioning . 主脚本文件将指示Godot, 一旦你的插件被激活后, 它将在编辑器中做什么.
脚本文件
创建插件后, 对话框会自动为你打开EditorPlugin脚本. 该脚本有两个要求, 你不能改变: 它必须是一个 tool
脚本, 否则将无法在编辑器中正常加载;它必须继承 EditorPlugin.
警告
除了这个 EditorPlugin 脚本之外,插件用到的其他 GDScript 也 必须是工具脚本。没有 tool
的 GDScript 在导入编辑器后都会像空文件一样!
处理好资源的初始化和清理是很重要的。一个好的做法是使用虚函数 _enter_tree() 来初始化你的插件,以及 _exit_tree() 来清理它。值得庆幸的是,对话框为你生成了这些回调。你的脚本应该看起来像这样:
GDScriptC#
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”(自定义类型)节点。虽然它们可以用于任何脚本语言,但功能比 Script 类系统少。如果你正在编写 GDScript 或 NativeScript,建议使用 Script 类代替。
要创建一个新的节点类型, 你可以使用来自 EditorPlugin 类的 add_custom_type() 这个函数. 这个函数可以向编辑器添加新的类型(节点或资源). 但是, 在你创建类型之前, 需要一个脚本, 作为类型的逻辑. 虽然该脚本不一定要使用 tool
关键字, 但可以添加它, 以便脚本在编辑器中运行.
在本教程中, 我们将创建一个简单的按钮, 在点击时打印出一条信息. 对此, 我们需要一个从 Button 扩展的简单脚本. 如果你愿意, 它也可以扩展 BaseButton :
GDScriptC#
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!");
}
}
这就是我们的基本按钮了. 你可以把它保存为插件文件夹中的 my_button.gd
. 你还需要一个16×16的图标来显示在场景树中. 如果你没有, 可以从引擎中抓取默认的, 并保存在你的 addons/my_custom_node
文件夹中, 作为 icon.png
, 或者使用默认的Godot标志( preload(“res://icon.png”) ). 如果需要, 你也可以使用SVG图标.
现在,我们需要把它作为一个自定义类型添加,以便它显示在新建 Node 的对话框中。为此,将 custom_node.gd
脚本改为以下内容:
GDScriptC#
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 中的说明激活它.
然后通过添加新节点来尝试:
当你添加节点时, 你可以看到它已经有你创建的脚本附加在上面. 给这个按钮设置一个文本, 保存并运行场景. 当你点击按钮时, 你可以在控制台中看到一些文字:
自定义窗口
有时, 您需要扩展编辑器并添加始终可用的工具. 一种简单的方法是添加一个带插件的新扩展面板. Docks只是基于Control的场景, 因此它们的创建方式与通常的GUI场景类似.
创建一个自定义栏好的方法和自定义节点一样. 在 addons/my_custom_dock
文件夹中创建一个新的 plugin.cfg
文件, 然后在其中添加以下内容:
GDScriptC#
[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
。填写之前见过的模板以获得良好的开端。
由于我们正在尝试添加新的自定义窗口, 因此我们需要创建窗口的内容. 这只不过是一个标准的Godot场景: 只需在编辑器中创建一个新场景然后编辑它.
对于编辑器停靠站, 根节点 必须是 Control 或其子类之一. 在本教程中, 您可以创建一个按钮. 根节点的名称也将是面板对话框中显示的名称, 因此请务必为其指定一个简短的描述性名称. 另外, 不要忘记在按钮上添加一些文字.
把这个场景保存为 my_dock.tscn
. 现在, 我们需要抓取我们创建的场景, 然后在编辑器中把它添加为一个栏目. 为此, 你可以依赖 add_control_to_dock() 这个函数, 它来自 EditorPlugin 类.
你需要选择一个停靠位置并定义要添加的控件, 也就是你刚刚创建的场景. 不要忘了在插件停用时 remove the dock . 脚本可以是这样的:
GDScriptC#
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
请注意, 虽然Dock最初会出现在其指定的位置, 但用户可以自由改变其位置, 并保存所产生的布局.
检查结果
现在是检查工作结果的时候了. 打开 项目设置 , 然后单击 插件 选项卡. 您的插件应该是列表中唯一的插件. 如果未显示, 请单击右上角的 更新 按钮.
您可以在 Status 列中看到该插件处于非激活状态; 点击状态选择 Active . 在您关闭设置窗口之前, 该扩展窗口应该可见. 您现在应该看到一个自定义窗口:
举一反三
现在您已经学会了如何制作基本插件, 您可以通过多种方式扩展编辑器. 可以使用GDScript将许多功能添加到编辑器中; 它是一种创建专业编辑器的强大方法, 无需深入研究C++模块.
您可以制作自己的插件来帮助自己或在 素材库 中分享它们,以便人们可以从您的工作中受益。
Registering autoloads/singletons in plugins
It is possible for editor plugins to automatically register autoloads when the plugin is enabled. This also includes unregistering the autoload when the plugin is disabled.
This makes setting up plugins faster for users, as they no longer have to manually add autoloads to their project settings if your editor plugin requires the use of an autoload.
Use the following code to register a singleton from an editor plugin:
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)