Godot4 EditorPlugin _handles 関数の引数の代替例

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、エディター機能を拡張するプラグインを作成する際に用いる EditorPlugin クラスの _handles イベント関数は、新たなノードが選択された際に呼び出されますが、複数選択時に渡される引数のクラスが利用できません
その現象の確認と、引数と似たデータを取得する対処法について紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。

確認用のプラグインの作成

EditorPlugin の _handles イベント関数で、選択されたノード群の情報を受け取るためには、プラグインを作成・有効化して、作成されたプラグイン用の gd スクリプトに _handles イベント関数をオーバーライドする必要があります。

プラグインを作成するには、メニュー「プロジェクト」→「プロジェクト設定」で表示される「プロジェクト設定」ダイアログの「プラグイン」タブ「新しいプラグインを作成」ボタンを押します。

Godot4 FitFontSize プラグインの作成1


プラグイン名、サブフォルダー、説明、作者などのプラグインの情報を入力して「作成」ボタンを押します。

「今すぐアクティブ化」チェックがデフォルトでチェックされているので、自動的にプラグインは有効化されます。
手動で有効化する場合は、メニュー「プロジェクト」→「プロジェクト設定」で表示される「プロジェクト設定」ダイアログの「プラグイン」タブのそのプラグインの「有効」をチェックしてください。

Godot4 FitFontSize プラグインの作成2

addons フォルダ内の指定したサブフォルダにプラグイン用の gd スクリプトが作成されました。

Godot4 FitFontSize プラグインの作成3

プラグインの設定は、同時に作成された pluguin.cfg で確認できます。

[plugin]

name="ScFitFontSize"
description="選択されているコントロール派生のノードのサイズから、テキスト描画サイズがはみでない、最大のフォントサイズを設定します。"
author="SakuraCrowd"
version=""
script="sc_fit_font_size.gd"

次の章では、作成された sc_fit_font_size.gd ファイルをダブルクリックして編集しまて、 _handles の引数について確認します。

単一・複数ノード選択時の _handles の引数の出力結果

作成したプラグインの gd ファイルを以下のスクリプトで上書きします。

以下のスクリプトでは、 EditorPlugin クラスの _handles イベント関数をオーバーライドして、 システムから _handles を呼び出してもらい、 object (Object クラス)の引数の値を文字列で出力します。

@tool
extends EditorPlugin

## ノードを選択した際に渡される [param object] のクラス名を get_class() から得た文字列で確認します。
## 単一選択では、ノードの名前:<クラス名#数字の番号> でした。
## 複数選択では、<MultiNodeEdit#-数字の番号> でした。
##
## プラグインが特定のタイプのオブジェクト (リソースまたはノード) を編集する場合は、この関数を実装します。
## true を返すと、エディターが関数 _edit と _make_visible を要求したときに呼び出される関数を取得します。
##  _forward_canvas_gui_input メソッドと _forward_3d_gui_input メソッドを宣言している場合、これらも呼び出されます。
## 参照: https://docs.godotengine.org/en/stable/classes/class_editorplugin.html#class-editorplugin-private-method-handles
func _handles(object: Object) -> bool:
	print("object.get_class() = ", object.get_class(), ", print(object) = ", object)
	return false

スクリプトを上書き保存して、プラグインが有効であることを確認します。
※メニュー「プロジェクト」→「プロジェクト設定」で表示される「プロジェクト設定」ダイアログの「プラグイン」タブで「有効」にチェックが入っているか確認できます。

引数の確認ために、「シーン」ドックで、1つのノードをクリックするだけの選択(単一選択)と Shift や Ctrl を押しながらクリックして複数のノードを選択(複数選択)する動作をおこないます。

ノードを単一選択した場合、呼び出された _handles の引数には「ノード名:<クラス名#数字の番号>」が表示されます。
ノードを複数選択した場合、呼び出された _handles の引数には「<MultiNodeEdit#-数字の番号」が表示されます。

Godot4 EditorPlugin ノード選択時に渡される Object のクラスの単体・複数での違い

object.get_class() = Button, print(object) = OpenButton:
object.get_class() = Button, print(object) = CloseButton:
object.get_class() = RichTextLabel, print(object) = MainTextRichTextLabel:
object.get_class() = RichTextLabel, print(object) = TitleRichTextLabel:
object.get_class() = ColorRect, print(object) = BackGroundColorRect:
object.get_class() = Control, print(object) = CreditScreen:
object.get_class() = Control, print(object) = CreditScreen:
object.get_class() = MultiNodeEdit, print(object) =
object.get_class() = Button, print(object) = OpenButton:
object.get_class() = MultiNodeEdit, print(object) =

※ 最後の <> で囲まれている値はコピーミスのため貼り付けられませんでした。スクリーンショット画像を参照してください。

複数ノード選択時に引数のクラス MultiNodeEdit のパースエラー

以下のスクリプトでは、複数選択時の _handles の object 引数の print 出力で表示された MultiNodeEditクラスとして扱い引数を型変換する処理を追加しました。
※ MultiNodeEdit について検索すると GitHub の godotengine の cpp ファイルが見つかります。 godot/editor/multi_node_edit.cpp at master · godotengine/godot · GitHub

@tool
extends EditorPlugin

## ノードを選択した際に渡される [param object] のクラス名を get_class() から得た文字列で確認します。
## 単一選択では、ノードの名前:<クラス名#数字の番号> でした。
## 複数選択では、<MultiNodeEdit#-数字の番号> でした。
##
## プラグインが特定のタイプのオブジェクト (リソースまたはノード) を編集する場合は、この関数を実装します。
## true を返すと、エディターが関数 _edit と _make_visible を要求したときに呼び出される関数を取得します。
##  _forward_canvas_gui_input メソッドと _forward_3d_gui_input メソッドを宣言している場合、これらも呼び出されます。
## 参照: https://docs.godotengine.org/en/stable/classes/class_editorplugin.html#class-editorplugin-private-method-handles
func _handles(object: Object) -> bool:
	print("object.get_class() = ", object.get_class(), ", print(object) = ", object)
	if object is Button:
		pass
	if object is MultiNodeEdit:
		pass
	return false

しかし、このスクリプトを上書き保存すると、以下のパースエラーが発生して、 MultiNodeEdit をクラスとして扱えません。

res://addons/sc_fit_font_size/sc_fit_font_size.gd:22 – Parse Error: Could not find type “MultiNodeEdit” in the current scope.

GD Scirpt のエディターで MultiNodeEdit をクラス名として使った際に出力などに表示されたパースエラー

パースエラーは、Script ワークスペースの下側で確認できます。

Godot4 MultiNodeEdit クラス名は確認できてもそのクラス名を判定などに用いるとパースエラーになりました

また、別のタイミング(再現手順は不明)では、出力下パネルにエラーメッセージとして表示されました。

Godot4 MultiNodeEdit クラス名は確認できてもそのクラスでの判定などはできない

引数に似たデータを取得するスクリプトによる対処例

前述のとおり、EditorPlugin クラスの _handles イベント関数で渡される現在選択されているノード(オブジェクト?)の情報は、複数選択の場合、MultiNodeEdit 型のオブジェクトにどのようにアクセスしてよいかわからず、プラグインの処理対象になるかを判定して戻り値 (bool) を返せません

検索すると、同様の問題の回避策として、引数のかわりに、EditorSelection から選択中のノード群を得て、それをもとにプラグインの処理対象かを判定する方法が紹介されていました。

Just hit @strutcode‘s issue. Is there some reason this isn’t exposed? Else we can just add it no?

get_editor_interface().get_selection().get_selected_nodes() allows to workaround. Not an ideal interface but workable.

get_editor_interface().get_selection().get_selected_nodes() を使用すると回避策が可能になります。理想的なインターフェイスではありませんが、実用的です
Expose MultiNodeEdit as a scriptable class · Issue #8067 · godotengine/godot-proposals と Google 翻訳

以下は、その回避策の実装例です。

2つの関数のうち、2番目の get_editor_plugin_handles_argument 関数が、先ほどの情報をもとに作成した「選択中のノード群」を得る関数です。
1番目の関数 _handles 関数では、引数の object のかわりに、その関数から得た「選択中のノード群」の情報をもとに、プラグインの処理対象かを判定して戻り値を返します。

@tool
extends EditorPlugin

## Control クラスまたはその派生クラスが選択されたノード群に含まれていれば true を返し、他は false を返します。
## 以下は公式の説明の Google 翻訳です。
## プラグインが特定のタイプのオブジェクト (リソースまたはノード) を編集する場合は、この関数を実装します。
## true を返すと、エディターが関数 _edit と _make_visible を要求したときに呼び出される関数を取得します。
##  _forward_canvas_gui_input メソッドと _forward_3d_gui_input メソッドを宣言している場合、これらも呼び出されます。
## 参照: https://docs.godotengine.org/en/stable/classes/class_editorplugin.html#class-editorplugin-private-method-handles
func _handles(object: Object) -> bool:
	print("object.get_class() = ", object.get_class(), ", print(object) = ", object)
	# 引数と同等と思われる、選択されているノード群の配列を取得します。詳細は呼び出している関数の説明を参照してください。
	var selected_nodes: Array[Node] = get_editor_plugin_handles_argument(self)
	# 選択されているノード群のノード1つずつのクラス名などを出力します。
	for node in selected_nodes:
		print("node.get_class() = ", node.get_class(), ", print(node) = ", node)
	return false

## _handles の引数とおそらく同等のものを別の方法で取得します。
## 注意: _handles の引数は Object クラスですが、ここで得られるのは Node クラスの配列です。
##
## EditorPlugin _handles イベント関数で渡される引数は、複数のノードなどを選択している場合 MultiNodeEdit と呼ばれる
## アクセスできないクラスのオブジェクトが渡されます。(Godot4.3 2025/02/20 現在)
## その対処法として、別の方法で現在選択されている object 群を取得して、その配列を返します。
## 参照: Expose MultiNodeEdit as a scriptable class · Issue #8067 · godotengine/godot-proposals - https://github.com/godotengine/godot-proposals/issues/8067
static func get_editor_plugin_handles_argument(editor_plugin: EditorPlugin) -> Array[Node]:
	var editor_interface: EditorInterface = editor_plugin.get_editor_interface()
	var editor_selection: EditorSelection = editor_interface.get_selection()
	var selected_nodes: Array[Node] = editor_selection.get_selected_nodes()
	return selected_nodes

テスト

プラグインを有効にした状態で、「シーン」ドックで Shift や Ctrl キーを押しながらノードをクリックすることで複数選択してみましょう。

ノードを選択すると _handles 関数が呼ばれ、その時点で選択されている複数のノード群を配列で受け取り、その内容を print 出力できました。

これにより引数のアクセスできない object のデータに似た情報を取得して代替処理を行うことができました。
※ MultiNodeEdit とは異なるため、完全な代替というわけではありません

Godot4 EditorPlugin _handles の object 引数と似た値を選択ノード群を取得する関数から得ました。

object.get_class() = Button, print(object) = OpenButton:
node.get_class() = Button, print(node) = OpenButton:
object.get_class() = MultiNodeEdit, print(object) =
node.get_class() = Button, print(node) = OpenButton:
node.get_class() = RichTextLabel, print(node) = MainTextRichTextLabel:

※ 最後の <> で囲まれている値はコピーミスのため貼り付けられませんでした。スクリーンショット画像を参照してください。

以上で、複数選択時_handles 関数が呼ばれた際に、どのノードたちが選択されているかを知ることができるようになりました。
#根本的に解決するには、エンジンのほうで MultiNodeEdit クラスを利用できるようにするなどの対応が必要だと思います。

まとめ

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、エディター機能を拡張するプラグインを作成する際に用いる EditorPlugin クラスの _handles イベント関数は、新たなノードが選択された際に呼び出されますが、複数選択時に渡される引数のクラスが利用できません
今回は、その現象の確認と、引数と似たデータを取得する対処法について紹介しました。

参照サイト Thank You!

記事一覧 → Compota-Soft-Press

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました