制作主屏幕插件

本教程涵盖的内容

如图所示 制作插件 页面,制作一个扩展编辑器的基本插件相当容易。这个插件机制还允许您在编辑器的中心部分创建新的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压缩场景的常量 (MainPanelSidePanel )我们将使用这些资源来实例这两个场景。

这个 _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旁边观察一个新按钮。您还会注意到左侧停靠处有一个新选项卡。尝试单击侧面板和主面板中的按钮:事件由相应的目标场景发出并捕获,以更改其中的标签标题。