制作插件
下文仅针对2.1版本。
关于插件
插件是为编辑器扩展出更多有用工具的重要方式。它可以完全用GDScript和标准场景开发,甚至都不需重新加载编辑器就可生效。不像模块,你无需创建C++代码、也无需重新编译整个引擎。这使得插件可能不够强大,但仍能用之完成很多事情。注:插件与你已经制作的任何场景没有不同,除了它是通过脚本添加功能。
该手册将会通过两个简单插件的创建来让你理解其工作原理并自行开发。首先,在项目中添加一个自定义节点到任意场景,然后就会有一个自定义Dock添加到编辑中。
创建插件
开始前,先新建一个空项目,用于开发和 测试插件。
项目目录下,有存放插件的标准目录addons/plugin_name
,所以,在addons`目录中创建一个叫
my_custom_node``的目录,目录结构类似于:
创建plugin.cfg
文件,Godot还不能打开这种文件所以必须在外部编辑器中编辑其内容:
[plugin]
name="My Custom Node"
description="A custom node made to extend the Godot Engine."
author="Your Name Here"
version="1.0"
script="custom_node.gd"
这是有关你这个插件的元数据,需要设置名称和描述以便用户理解其作用。当插件激活时,会加载你指定的主脚本文件。指定版本号后,用户可以去判定是否是一个过期版本(关于语义化版本规范可以参看:http://semver.org/lang/zh-CN/)。
脚本文件
打开脚本编辑器(F3)并创建一个在 my_custom_node
目录下的名为custom_node.gd
的GDScript文件。该脚本有两点特殊要求:它必须是 tool
脚本;必须继承自EditorPlugin
类。
有项很重要的工作是初始化并清空资源。一种好的实践方式是用虚拟函数_enter_tree() <class_Node__enter_tree>
来初始化插件以及用_exit_tree() <class_Node__exit_tree>
来清空它。你可以删除默认的GDScript模板内容并用以下代码结构替换:
tool
extends EditorPlugin
func _enter_tree():
# Initialization of the plugin goes here
pass
func _exit_tree():
# Clean-up of the plugin goes here
pass
这段模板代码在开发新插件时一般都可以用到。
自定义节点
有时你想让多个节点拥有某种特定的行为,可能通过重用自定义场景或控件可实现这种需求;场景实例化在很多情况是有用的,但有时会显得累赘,尤其被用于多个项目中时。这时好的解决方案是制作一个插件,用于添加带有自定义行为的节点。
要新建一种节点类型,通过class_EditorPlugin
类的add_custom_type() <class_EditorPlugin_add_custom_type>
函数。该函数能给编辑器添加新的类型,可以是节点或资源。不过在创建类型之前,你需要一个脚本用于承载其逻辑。这种脚本不需要用tool
关键词来修饰,仅仅是让用户可以在编辑器中看到它。
我们来创建一个简单的按钮,效果是:当其被点击时,打印一条消息。我们需要一段简单脚本,继承自Button
类,也可以继承自BaseButton
类:
tool
extends Button
func _enter_tree():
connect("pressed", self, "clicked")
func clicked():
print("You clicked me!")
将代码文件命名为 button.gd
保存到插件目录。还需要一个16x16的小图标用来显示在场景树中。如果没有,可以暂时用场景中的默认图标。
我们来将其添加为自定义类型以便在Create New 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("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")
做完这个操作,在项目设置的插件列表中,这个插件应该就出现了,激活它,并试着添加一个新的节点来看看效果:
添加了节点后,你会看到脚本已经被附着到该节点上。设置按钮的文本,保存并运行场景。点击按钮,应该就能看到控制台中输出的文本:
自定义Dock
有时你需要通过扩展编辑器来添加已经存在的工具,一种简单的方式是通过插件添加一个新的Dock。Dock是基于控件的场景,所以没有新的知识点啦。
创建插件的方式与自定义节点的方式相似,所以在 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"
Dock的内容其实完全就是标准的Godot场景。
对于编辑器Dock来说,场景的根节点强制为Control
类或其子类。根节点的名称也将是出现在Dock选项卡上的名称,所以要剪短精炼,别忘了给按钮添加一段文本:
将场景保存为 my_dock.tscn
。
选取刚刚创建的场景,以Dock的形式添加到编辑器中 - 依赖EditorPlugin
类的add_control_to_dock()
的函数:
代码很直观,选定好Dock的位置。当插件失活时,要记得移除Dock:
tool
extends EditorPlugin
var dock # A class member to hold the dock during the plugin lifecycle
func _enter_tree():
# Initialization of the plugin goes here
# First 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 scene from the docks:
remove_control_from_docks( dock ) # Remove the dock
dock.free() # Erase the control from the memory
用户可以自由移动Dock的未知,并保存dock的布局位置。
检验结果
打开“Project Settings”,点击“Plugin”选项卡,你的插件应该出现在列表中,如果并未出现,点击右上角“Update”按钮:
在“Status”列中,显示该插件是未激活的,只要点击状态并选择“激活”即可,而Dock也会即时显示。
更深入的内容
既然你已学习了如何制作简单的插件,你就可以用很多很好的方式来扩展编辑器。通过GDScript可以给编辑器快速添加很多功能函数,从而创建出所需的特定编辑器,而无需研究C++模块。
你可以制作插件来助力自己的开发工作,也可以将这些插件分享到Godot的Asset Library以便更多的人受益。