メイン画面プラグイン(Main screen plugin)の作成

このチュートリアルの対象

プラグインの作成 ページに見られるように、エディタを拡張する基本的なプラグインを作成するのはかなり簡単です。このプラグインメカニズムにより、基本的な2D、3D、スクリプト、AssetLibビューと同様に、エディタの中央部分に新しいUIを作成することもできます。このようなエディタプラグインは、「メイン画面プラグイン」と呼ばれます。

このチュートリアルでは、基本的なメイン画面プラグインの作成について説明します。このプラグインの例を使用して、次のことを示します:

  • メイン画面プラグインを作成
  • メイン画面を別のプラグインGUI要素([インスペクタ]タブに似たタブパネルなど)にリンクする

簡単にするために、メイン画面プラグインの2つの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"

また、.cfg ファイルの script = プロパティが対象とするファイルを初期化します。この例では、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"


func get_plugin_icon():
   return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons")

このスクリプトの重要な部分は has_main_screen() 関数です。これはオーバーロードされているため true を返します。この関数は、プラグインのアクティブ化時にエディタによって自動的に呼び出され、このプラグインがエディタに新しいセンタービューを追加することを通知します。とりあえず、このスクリプトはそのままにしておき、後でまた説明します。

シーン

main_screen_plugin.gd ファイルは、プラグインの各UI要素のインスタンス化を担当し、それらの間の通信も管理します。

As a matter of fact, we wish to design each UI element in their own scene. Different scenes are not aware of each other unless they are both children of a parent scene, yet they will then require get_node("../sibling") accessors. Such practice is more likely to produce errors at runtime, especially if these scenes do not share the same parent node. This is why, they should only be allowed to access their children.

そのため、別のシーンに情報を伝えるための最良の設計は、シグナルを定義することです。UIシーン#1のユーザーアクションが別のUIシーン#2で何かをトリガーする必要がある場合、このユーザーアクションはシーン#1からシグナルを発信する必要があり、シーン#2はそのシグナルに接続されます。すべてのUIシーンは main_screen_plugin.gd スクリプトによってインスタンス化されるため、この1つのスクリプトはそれぞれのシーンを必要なシグナルに接続します。

注釈

If the main_screen_plugin.gd instantiates the UI scenes, won't they be sibling nodes then?

必ずしもそうではありません: このスクリプトは、エディタのシーンツリーの同じノードの子としてすべてのUIシーンを追加する場合がありますが、そうでない場合があります。そして、main_screen_plugin.gd スクリプトは、ノードではなくスクリプトであるため、インスタンス化されたシーンの親ノードではありません!このスクリプトは、インスタンス化されたシーンへの参照のみを保持します。

メイン画面のシーン

Panel ルートノードで新しいシーンを作成します。このルートノードを選択し、ビューポートで レイアウト メニューをクリックし、Rect全面 を選択します。また、インスペクタでSize FlagsのVerticalセクション内の Expand を有効にする必要があります。これで、パネルはビューポートで使用可能なすべてのスペースを使用します。それでは、ルートノードに新しいスクリプトを追加しましょう。 main_panel.gd という名前を付けます。

次に、このPanelノードに2つの子を追加します: 最初は Button ノードです。パネル上の任意の場所に配置します。次に、Label ノードを追加します。

次に、このボタンが押されたときの動作を定義する必要があります。これは シグナルの処理 ページでカバーされているため、このチュートリアルではこの部分について詳しく説明しません。Buttonノードを選択し、ノード サイドドックをクリックします。`` pressed()`` シグナルを選択して 接続... ボタンをクリックします(代わりに pressed() シグナルをダブルクリックすることもできます)。開いたウィンドウで、Panelノードを選択します(アタッチされたスクリプトですべての動作を一元化します)。デフォルトの関数名を保持し、関数の作成 トグルがオンになっていることを確認し、接続 を押します。これは main_panel.gd スクリプトに _on_Button_pressed() 関数を作成し、ボタンが押されるたびに呼び出されます。

ボタンが押されると、サイドパネルの 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!")

同様に、このメインシーンのLabelノードは、特定のシグナルを受信したときに値を表示する必要があります。この目的のために新しい _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 という名前を付けるか、前のセクションを再度たどって新しいシーンから再作成できます。ただし、新しいスクリプトを作成して、Panelルートノードにアタッチする必要があります。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

プラグインスクリプトで2つのシーンを接続する

プラグインが2つのGUIシーンをインスタンス化し、エディタの適切な場所に配置するように、main_screen_plugin.gd スクリプトを更新する必要があります。完全な 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"


func get_plugin_icon():
   # Must return some kind of Texture for the icon.
   return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons")

いくつかの特定の行が追加されました。最初に、2つのGUIパックシーン(MainPanel および SidePanel)を含む定数を定義しました。これらのリソースを使用して、両方のシーンをインスタンス化します。

_enter_tree() 関数は _ready() の前に呼び出されます。ここで実際に2つのGUIシーンをインスタンス化し、それらをエディタの特定の部分の子として追加します。サイドパネルの場合は、プラグインの作成 ページに示されている例に似ています: シーンをエディタドックに追加します。左側のドック、左上のタブに配置されるように指定しました。

EditorPlugin クラスは、メインビューポートに要素を追加する機能を提供しません。したがって、このビューポートを取得し、メインパネルインスタンスを子として追加するには、get_editor_interface().get_editor_viewport() を使用する必要があります。メインパネルを隠すために make_visible(false) 関数を呼び出して、プラグインを最初にアクティブ化したときに直接表示されないようにします。

_exit_tree() はとても簡単です。プラグインが非アクティブ化されると自動的に呼び出されます。メモリを温存するために、以前にインスタンス化された要素を queue_free() することが重要です。そうしないと、エレメントはエディタで事実上見えなくなりますが、メモリ内には残っています。メモリを解放しない場合、複数の非アクティブ化/再アクティブ化によりメモリ使用量が増加していきますが、これは良くありません。

最後に、必要に応じて make_visible() 関数がオーバーライドされ、メインパネルが非表示または表示されます。この関数は、ユーザーが2D、3D、スクリプトなどの別のメインビューポートボタンをクリックすると、エディタによって自動的に呼び出されます。

プラグインを試す

プロジェクト設定でプラグインを有効にします。メインビューポートの上にある2D、3D、スクリプトの横に新しいボタンがあります。また、左のドックに新しいタブがあります。サイドパネルとメインパネルの両方のボタンをクリックしてみてください。イベントが発生し、対応するターゲットシーンでキャッチされて、その中のラベルキャプションが変更されます。

If you would like to see a more complete example of what main screen plugins are capable of, check out the 2.5D demo projects here: https://github.com/godotengine/godot-demo-projects/tree/master/misc/2.5d