制作主屏幕插件¶
本教程涵盖的内容¶
如图所示 制作插件 页面,制作一个扩展编辑器的基本插件相当容易。这个插件机制还允许您在编辑器的中心部分创建新的uis,类似于基本的二维、三维、脚本和assetlib视图。这种编辑器插件被称为“主屏幕插件”。
本教程将引导您完成基本主屏幕插件的创建。通过这个插件示例,我们要演示:
创建主屏幕插件
将主屏幕链接到另一个插件GUI元素(如选项卡面板,类似于Inspector选项卡)
为了简单起见,主屏幕插件的两个GUI元素都包含在一个标签和一个按钮中。按一个元素的按钮将在另一个元素的标签节点上显示一些文本。
正在初始化插件¶
插件本身是一个godot项目。最好将其内容设置为 addons/my_plugin_name/
结构。根文件夹中唯一的文件是project.godot文件和项目图标。
在 addons/my_plugin_name/
文件夹,我们创建 plugin.cfg
文件如中所述 制作插件 页。
[plugin]
name="Main screen plugin demo"
description="A plugin that adds a main screen panel and a side-panel which communicate with each other."
author="Your Name Here"
version="1.0.0"
script="main_screen_plugin.gd"
我们还初始化 script=
性质 .cfg
文件。在我们的例子中, main_screen_plugin.gd
.
tool
extends EditorPlugin
func _enter_tree():
pass
func _exit_tree():
pass
func has_main_screen():
return true
func make_visible(visible):
pass
func get_plugin_name():
return "Main Screen Plugin"
这个脚本的重要部分是 has_main_screen()
函数,它被重载,因此返回true。这个函数在插件激活时由编辑器自动调用,告诉它这个插件向编辑器添加了一个新的中心视图。现在,我们将保留这个脚本,稍后再讨论。
场景¶
这个 main_screen_plugin.gd
文件将负责我们每个插件的UI元素实例化,它还将管理它们之间的通信。
实际上,我们希望在自己的场景中设计每个UI元素。不同的场景不会相互了解,除非它们都是父场景的子场景,但是它们需要 get_node("../brother")
存取器。这种做法更有可能在运行时产生错误,尤其是当这些场景不共享同一父节点时。这就是为什么,他们应该只被允许接触他们的孩子。
因此,为了将信息传递到另一个场景,最好的设计是定义信号。如果用户界面场景1中的用户操作必须触发另一个用户界面场景2中的某个内容,则此用户操作必须从场景1发出信号,场景2将连接到该信号。因为我们所有的UI场景都将由 main_screen_plugin.gd
脚本,这一个脚本还将把它们中的每一个连接到所需的信号。
注解
如果 main_screen_plugin.gd
实例化UI场景,它们不是兄弟节点吗?
不一定:该脚本可以将所有UI场景添加为编辑器场景树的同一节点的子节点,但可能不会。并且 main_screen_plugin.gd
脚本意志 not 是任何实例化场景的父节点,因为它是脚本,而不是节点!此脚本将只保存对实例化场景的引用。
主屏幕场景¶
使用 Panel
根节点。选择此根节点,然后在视区中单击 Layout
菜单和选择 Full Rect
. 面板现在使用了视区中的所有可用空间。现在,让我们在根节点上添加一个新脚本。命名它 main_panel.gd
.
然后我们将2个子节点添加到此面板节点:首先 Button
节点。把它放在面板上的任何地方。
现在,我们需要定义按下此按钮时的行为。这包括在 Handling a signal 页,因此本教程中不会详细描述此部分。选择按钮节点并单击 Node
侧坞。选择 pressed()
发出信号并单击 Connect
按钮(也可以双击 pressed()
代之以信号)。在打开的窗口中,选择面板节点(我们将在其附加脚本中集中所有行为)。保留默认函数名,确保 Make function
打开并点击 Connect
. 这将创建一个 on_Button_pressed()
功能在 main_panel.gd
脚本,每次按下按钮时都会调用该脚本。
当按钮按下时,我们要侧面板的 Label
显示特定文本的节点。如上所述,我们无法直接访问目标场景,因此我们将发出一个信号。这个 main_screen_plugin.gd
然后,脚本将此信号连接到目标场景。让我们继续 main_panel.gd
脚本:
tool
extends Panel
signal main_button_pressed(value)
func on_Button_pressed():
emit_signal("main_button_pressed", "Hello from main screen!")
同样,当主场景的标签节点接收到特定的信号时,它必须显示一个值。让我们创建一个新的 _on_side_button_pressed(text_to_show)
为此目的的功能:
func _on_side_button_pressed(text_to_show):
$Label.text = text_to_show
主屏幕面板已完成。将场景另存为 main_panel.tscn
.
选项卡式面板场景¶
选项卡式面板场景几乎与主面板场景相同。你可以复制 main_panel.tscn
文件并命名新文件 side_panel.tscn
或者通过再次跟踪上一节从新场景重新创建它。但是,必须创建一个新脚本并将其附加到面板根节点。另存为 side_panel.gd
. 它的内容略有不同,因为发出的信号和目标函数的名称不同。以下是脚本的完整内容:
tool
extends Panel
signal side_button_pressed(value)
func on_Button_pressed():
emit_signal("side_button_pressed", "Hello from side panel!")
func _on_main_button_pressed(text_to_show):
$Label.text = text_to_show
连接插件脚本中的两个场景¶
我们现在需要更新 main_screen_plugin.gd
编写脚本,让插件实例我们的2个GUI场景,并将它们放置在编辑器中的正确位置。这是满的 main.gd
:
tool
extends EditorPlugin
const MainPanel = preload("res://addons/my_plugin_name/main_panel.tscn")
const SidePanel = preload("res://addons/my_plugin_name/side_panel.tscn")
var main_panel_instance
var side_panel_instance
func _enter_tree():
main_panel_instance = MainPanel.instance()
side_panel_instance = SidePanel.instance()
# Add the main panel to the editor's main viewport.
get_editor_interface().get_editor_viewport().add_child(main_panel_instance)
# Add the side panel to the Upper Left (UL) dock slot of the left part of the editor.
# The editor has 4 dock slots (UL, UR, BL, BR) on each side (left/right) of the main screen.
add_control_to_dock(DOCK_SLOT_LEFT_UL, side_panel_instance)
# Hide the main panel
make_visible(false)
func _exit_tree():
main_panel_instance.queue_free()
side_panel_instance.queue_free()
func _ready():
main_panel_instance.connect("main_button_pressed", side_panel_instance, "_on_main_button_pressed")
side_panel_instance.connect("side_button_pressed", main_panel_instance, "_on_side_button_pressed")
func has_main_screen():
return true
func make_visible(visible):
if visible:
main_panel_instance.show()
else:
main_panel_instance.hide()
func get_plugin_name():
return "Main Screen Plugin"
添加了一些特定行。首先,我们定义了包含两个GUI压缩场景的常量 (MainPanel
和 SidePanel
)我们将使用这些资源来实例这两个场景。
这个 _enter_tree()
函数在前面调用 _ready()
. 这就是我们实际实例2个GUI场景的地方,并将它们添加为编辑器特定部分的子级。侧面板外壳类似于中所示的示例 制作插件 佩奇:我们将场景添加到一个编辑器基座中。我们指定它将被放置在左侧的Dock,左上角的选项卡中。
EditorPlugin
类不提供在主视区中添加元素的任何函数。因此我们必须使用 get_editor_interface().get_editor_viewport()
要获取此视区并将主面板实例作为子级添加到其中。我们称之为 make_visible(false)
函数隐藏主面板,以便在第一次激活插件时不会直接显示。
这个 _exit_tree()
很简单。当插件被停用时,它会自动调用。那么重要的是 queue_free()
先前为保存内存而实例化的元素。如果不这样做,元素在编辑器中实际上是不可见的,但它们仍将存在于内存中。多次取消激活/重新激活会增加内存使用量,而不会释放内存,这是不好的。
最后 make_visible()
函数被重写以根据需要隐藏或显示主面板。当用户单击另一个主视区按钮(如二维、三维或脚本)时,编辑器会自动调用此函数。
试试这个插件¶
激活项目设置中的插件。您将在主视区上方的2d、3d和script旁边观察一个新按钮。您还会注意到左侧停靠处有一个新选项卡。尝试单击侧面板和主面板中的按钮:事件由相应的目标场景发出并捕获,以更改其中的标签标题。