Godot4 選択ノードの解除・再選択・ルートノードの選択追加のスクリプト例

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、作成した EditorPlugin 派生のプラグインの機能を使って、選択中のノード群の選択解除再選択ルートノード選択ノード群に追加するスクリプト例を紹介します。
Godot Engine 4.3 で、プラグインが有効になった直後_handles が呼び出されず描画などが行えない問題に対処します。
※一時的な対処を想定しています。根本的な解決方法としてはシステムが _enable_plugin イベント関数呼び出しの直後に現在選択中のノードを引数に _handles を呼ぶべきではないかと思います。

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

前回の記事

サンプルコードを用いて、 2D ワークスペース上のマウスポインタの位置に円を EditorPlugin を継承したプラグインクラスで描画する処理を実装・確認しました。

 https://compota-soft.work/wp1/wp-admin/post.php?post=44751&action=edit

また、プラグインが有効になった直後に _handles イベント関数が呼び出されずプラグイン描画が行えない問題と、手動でノードを再選択すると対処できることも確認しました。

今回は、手動で行っていたノードの再選択をスクリプトで行います。

ノード群の選択解除・再選択・ルートノード選択のスクリプト例

以下のスクリプトは、自作の静的関数を定義したスクリプトファイル sakuracrowd_util.gd に追加しています。
ファイル名は適宜変えて、静的関数を定義するためのファイルを用意して、以下のスクリプトを追加します。

独自のスクリプトファイルを作成する手順は以下を参照してください。

スクリプトには4つの関数が定義してあります。2~4番目に定義されている関数は以下です。

  • reselect_nodes : 選択中のノード群を再選択する関数
  • deselect_nodes: ノード群を選択解除する関数
  • add_root_node_to_selection: ルートノードを選択ノード群に追加する関数

1番目に定義されている request_call_editor_plugin_handles_event 関数は、それらを利用して、EditorPlugin クラスの _handles イベント関数が呼ばれるように促す関数です。

前回の記事で、 _handles は別のノードを選択すると呼ばれることがわかったので、それをスクリプトで行っています。
※詳細はスクリプト内のコメントを参照してください。
※最初の2行はファイルの冒頭に一度だけ記述してください。 class_name のあとにはクラス名を指定します。

extends Object
class_name SakuraCrowdUtil

## [method EditorPlugin._handles] イベント関数がシステムから呼び出されるように促します。
## 方法として、選択中のノードの再選択([method SakuraCrowdUtil.reselect_nodes])、
## 選択されていない場合はルートノードの選択([method SakuraCrowdUtil.add_root_node_to_selection])を行います。
## いずれかの方法を行った場合は true, それ以外は false を返します。
static func request_call_editor_plugin_handles_event(editor_plugin: EditorPlugin) -> bool:
	if reselect_nodes(editor_plugin) == false:
		if add_root_node_to_selection(editor_plugin) == false:
			print("SakuraCrowdUtil.request_call_editor_plugin_handles_event: 何も行いませんでした。")
			return false
		else:
			print("SakuraCrowdUtil.request_call_editor_plugin_handles_event: add_root_node_to_selection を行いました。")
	else:
		print("SakuraCrowdUtil.request_call_editor_plugin_handles_event: reselect_nodes を行いました。")
	return true

## 現在選択されているノード群を一度解除してから再び選択します。
## 選択されているノードがない場合はルートノードを再び選択します。
## ルートノードがない場合は何もしません。
## 再選択を行った場合は true, それ以外は false を返します。
static func reselect_nodes(editor_plugin: EditorPlugin) -> bool:
	var editor_interface: EditorInterface = editor_plugin.get_editor_interface()
	
	# すべての選択中のノードの選択を解除して、そのノード群を取得します。
	var deselected_nodes: Array[Node] = deselect_nodes(editor_plugin)
	
	if deselected_nodes.size() > 0:
		# 選択解除したノード群を再選択します。
		for node in deselected_nodes:
			editor_interface.get_selection().add_node(node)
		print("SakuraCrowdUtil.reselect_nodes: 選択中のノードを再選択しました。")
		return true
	return false

## 選択中のノード群を解除します。
## 解除したノード群の配列を返します。配列の要素数 size() は 0 かもしれません。
static func deselect_nodes(editor_plugin: EditorPlugin) -> Array[Node]:
	var editor_interface: EditorInterface = editor_plugin.get_editor_interface()
	
	# 選択中のノード群を取得します。
	var selected_nodes: Array = editor_interface.get_selection().get_selected_nodes()
	
	# 選択中のノードを1つずつ解除します。
	if selected_nodes.size() > 0:
		for node in selected_nodes:
			editor_interface.get_selection().remove_node(node)
		print("SakuraCrowdUtil.deselect_nodes: 選択中のノードを選択解除しました。")
	
	return selected_nodes

## ルートノードを選択中のノードに追加します。
## 追加した場合は true, それ以外は false を返します。
static func add_root_node_to_selection(editor_plugin: EditorPlugin) -> bool:
	var editor_interface: EditorInterface = editor_plugin.get_editor_interface()
	
	# 選択されているノードがない場合、ルートノードを再選択します。
	var scene_tree: SceneTree = editor_plugin.get_tree()
	var root_node: Node = scene_tree.edited_scene_root
	if root_node:
		editor_interface.get_selection().add_node(root_node)
		print("SakuraCrowdUtil.add_root_node_to_selection: ルートノードを選択しました。")
		return true
	else:
		print("SakuraCrowdUtil.add_root_node_to_selection: ノードが選択されていませんでしたし、ルートノードもありませんでした。")
	return false

選択中のノードの変更に用いた関数

ノードを選択する操作は、 EditorInterface を使用します。
EditorInterface は、 EditorPlugin.get_editor_interface() で取得できます。
EditorPlugin はプラグインの派生元なので self などから利用できます。

選択中のノードの配列は、 editor_interface.get_selection() で EditorSelection を取得して、editor_selection.get_selected_nodes() で Array[Node] として取得できます。

選択中のノードを追加するには、editor_selection.add_node(node)、除去するには editor_selection.remove_node(node) を呼び出します。

再選択の処理を前回作成したプラグインで呼び出す

前回作成した 2D ワークスペース上のマウスポインタの位置に円を描画する公式サイトのサンプルを使ったプラグインは、有効にした直後、別のノードを選択するまで _handles 関数が呼ばれないため、描画処理ができませんでした。

そのプラグインのスクリプトの _enable_plugin イベント関数で、今回作成した request_call_editor_plugin_handles_event 関数を呼び出す処理を追加します。

他のスクリプトの静的関数を呼び出すには、そのスクリプトのクラス名のあとに . をつけて関数呼び出しを書きます。
例では SakuraCrowdUtil がクラス名で、 request_call_editor_plugin_handles_event(self) が関数呼び出しです。
※クラス名は、そのスクリプトファイルの class_name で定義します。

## ユーザーがプロジェクト設定ウィンドウの [プラグイン] タブで EditorPlugin を有効にすると、エンジンによって呼び出されます。
func _enable_plugin():
	print("_enable_plugin called")
	# 有効になった直後に、 _handles イベント関数の呼び出しを促します。
	SakuraCrowdUtil.request_call_editor_plugin_handles_event(self)
	return

その結果、プラグインが有効になった直後に、ノードの再選択をスクリプトから行うことで、 _handles イベント関数を直後に呼び出してもらい、そのあとに描画のイベント関数も呼び出してもらえるようになりました。

メニュー「プロジェクト」→「プロジェクト設定」で「プロジェクト設定」ダイアログを開き、「プラグイン」タブを選択します。

その中の、自作プラグイン ScPathTool の「有効」を OFF にしてから再び ON にすることで、有効になった直後のプラグインの状況になります。

前回は、ノードを手動で選択しないと 2D ワークスペースにプラグインによる円の描画はされませんでしたが、今回は _enable_plugin イベント関数で自作関数を呼び出してスクリプトからノードの再選択をしたので、手動でノードを選択しなくても 2D ワークスペースに円が描画されました。

print 文の出力でも、プラグインを有効にした直後に呼び出される _enable_plugin イベント関数自作関数 request_call_editor_plugin_handles_event を呼び出しノードの再選択をした直後に _handles イベント関数呼び出せたことが確認できます。

その後、プラグインによる描画 (_forward_canvas_force_draw_over_viewport) と入力処理 (_forward_canvas_gui_input) に必要な2つのイベント関数が呼ばれていることが確認できます。

_disable_plugin called
ScPathTool plugin を終了します
ScPathTool plugin を初期化します
_enable_plugin called
SakuraCrowdUtil.deselect_nodes: 選択中のノードを選択解除しました。
SakuraCrowdUtil.reselect_nodes: 選択中のノードを再選択しました。
SakuraCrowdUtil.request_call_editor_plugin_handles_event: reselect_nodes を行いました。
_handles called. object = TilemapStage:
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_gui_input called.InputEventMouseMotion: button_mask=0, position=((182, 1)), relative=((-3, 5)), velocity=((-231.6714, 318.5482)), pressure=0.00, tilt=((0, 0)), pen_inverted=(false)
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_gui_input called.InputEventMouseMotion: button_mask=0, position=((181, 5)), relative=((-1, 4)), velocity=((-231.6714, 318.5482)), pressure=0.00, tilt=((0, 0)), pen_inverted=(false)
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_gui_input called.InputEventMouseMotion: button_mask=0, position=((179, 10)), relative=((-2, 5)), velocity=((-231.6714, 318.5482)), pressure=0.00, tilt=((0, 0)), pen_inverted=(false)
_forward_canvas_force_draw_over_viewport called.@CanvasItemEditorViewport@9135:
_forward_canvas_gui_input called.InputEventMouseMotion: button_mask=0, position=((176, 17)), relative=((-3, 7)), velocity=((-192.8083, 446.9646)), pressure=0.00, tilt=((0, 0)), pen_inverted=(false)

まとめ

今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、作成した EditorPlugin 派生のプラグインの機能を使って、選択中のノード群の選択解除再選択ルートノード選択ノード群に追加するスクリプト例を紹介しました。
Godot Engine 4.3 で、プラグインが有効になった直後_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をコピーしました