無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、 EditorPlugin クラスを用いて追加したツールメニューアイテムで、独自のエディタ拡張機能を実行した後に、EditorUndoRedoManager を用いて Undo, Redo でそのアクションを行う前に戻したり、再びやり直したりする実装例を紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。
前回の記事
前回は、EditorPlugin クラスを用いて追加したツールメニューアイテムを実行した際に、その時点で選択しているノード群を自動的に編集(例としてフォントサイズを調節)するスクリプト例を紹介しました。
しかし、 Ctrl + Z キーを押してもツールメニューの処理(例ではフォントサイズの調整)を実行する前に戻せなかったので undo, redo を実装します。
プラグインでツールメニューを呼び出す実装
この記事のスクリプトはプラグインとして登録された gd ファイルに記述しています。
プラグインでツールメニューを呼び出す実装例については以下の記事を参照してください。
Undo, Redo の実装の主な流れ
EditorPlugin クラスを用いてエディタ拡張を実装している場合、そのメンバ関数 get_undo_redo() で EditorUndoRedoManager オブジェクトを取得して、そのオブジェクトのメンバ関数を使ってエディタ上の他と同様の Undo, Redo の処理を実装できます。
以下は、EditorPlugin で追加したツールメニューが選択された際に呼び出される関数内で、 Undo, Redo を設定しながら、そのエディタ拡張機能を実行している例です。

EditorUndoRedoManager オブジェクトのメンバ関数 create_action(“アクション名”) ~ commit_action() までの間に add_do_* 系や add_undo_* 系のメンバ関数で、実行する任意のオブジェクトのメンバ関数やプロパティの変更などの手続きを登録します。
最後に commit_action() を呼ぶことで、create_action(“アクション名”) 以降に、add_do_* 系や add_undo_* 系のメンバ関数で、登録した実行 (do) する手続き、 Undo(元に戻す)のための手続きが、そのアクションと関連付けて登録され、その登録した一連の実行 (do) の手続きが実行されます。
Undo, Redo のスクリプト例
EditorUndoRedoManager を使った Undo, Redo の実装例です。
例として、選択中のノード(1番目)の名前を Piyo に変更するエディタ拡張です。
Undo すると元の名前に戻るように、以前の名前を設定する手続きも add_undo_property 関数で登録されています。
@tool
extends EditorPlugin
## 選択されているノード群にテキストを持ったコントロールがある場合に、
## コントロールのサイズからはみ出ない最大のサイズにフィットしたフォントサイズに自動調節するエディタ拡張です。
## メニュー「プロジェクト」→「ツール」に追加されたメニューアイテムを選択することで実行されます。
## メニューアイテムの表示名です。
var tool_menu_item_name: StringName = "Sc Fit Font Size"
## プラグインの初期化処理を定義します。
## プラグイン (プロジェクト設定ダイアログ>プラグイン>有効) を有効にした直後や、プラグインが有効な状態のプロジェクトを開いた際に呼び出されます。
func _enter_tree():
# Initialization of the plugin goes here.
# メニュー「プロジェクト」→「ツール」にサブメニューを追加します。メニュー選択時に、第二引数のメンバ関数を呼び出します。
add_tool_menu_item(tool_menu_item_name, Callable(self, "_on_menu_item_sc_fit_font_size"))
print("sc_fit_font_size.gd: _enter_tree called")
## プラグインの後片付けの処理を定義します。
## プラグインを無効 (プロジェクト設定ダイアログ>プラグイン>有効) にした直後や、プラグインが有効な状態のプロジェクトを閉じた際に呼び出されます。
func _exit_tree():
# Clean-up of the plugin goes here.
#
remove_tool_menu_item(tool_menu_item_name)
print("sc_fit_font_size.gd: _exit_tree called")
# EditorPlugin で Undo, Redo を実装する主な流れです。
# 例として選択しているノード(1番目)の名前を Piyo に変更する処理の実行, Redo と、元の名前に戻す Undo を実装します。
func _on_menu_item_sc_fit_font_size() -> void:
# 例として、操作対象に選択中のノードの1番目を選びます。 self は EditorPlugin クラスです。
var editor_interface: EditorInterface = self.get_editor_interface()
var editor_selection: EditorSelection = editor_interface.get_selection()
var selected_nodes: Array[Node] = editor_selection.get_selected_nodes()
if selected_nodes.size() < 1:
# 選択しているノードがない場合は何もしません。
return
var target_node: Node = selected_nodes[0]
# 例として、ノードの名前を変更します。 Undo では、元の名前に戻します。
var action_name: StringName = "Rename Node Piyo"
var property_name: StringName = "name"
var old_name: StringName = target_node.name
var new_name: StringName = "Piyo"
# Undo, Redo 操作を実装するためのオブジェクトです。
var editor_undo_redo_manager: EditorUndoRedoManager = get_undo_redo()
# アクションを登録します。
editor_undo_redo_manager.create_action(action_name)
# ----- ↓ 今回のアクションで実行するコマンド、元に戻すためのコマンドをを 1 個以上登録します ----
# 実行(または redo)する際に、指定したオブジェクトのプロパティの値の変更のコマンドを追加します。
editor_undo_redo_manager.add_do_property(target_node, property_name, new_name)
# undo する際に、指定したオブジェクトのプロパティの値をもとに戻すコマンドを追加します。
editor_undo_redo_manager.add_undo_property(target_node, property_name, old_name)
# 他にも、add_do_method, add_undo_method でメンバ関数呼び出しを登録できます。
# プロパティの変更と異なる処理を行う場合に使用します。
#
# また実行 (do) や元に戻す処理 (undo) が巻き戻差れた際に消えてしまうオブジェクトを保持する
# add_do_reference, add_undo_reference メンバ関数もあります。
# ----- ↑ 今回のアクションで実行するコマンド、元に戻すためのコマンドをを 1 個以上登録しました ----
# add_do_* 系の関数を全て実行します。
# あとで Undo の指示がきた場合は、add_undo_* 系の関数で登録したコマンドが実行されます
editor_undo_redo_manager.commit_action()
return
テスト
初めに、処理が実行されるか(例ではノードの名前が Piyo に変わるか)を確認します。
シーンドックでノードを選択(例では Button ノード)します。

次に、登録しておいたツールメニューを、メニュー「プロジェクト」→「ツール」→「Sc Fit Font Size」と選択して実行します。

選択したノードの名前が Piyo に変わり、出力ボトムパネルには、 create_action で指定したアクション名が表示されました。

次に、 Ctrl + Z キーを押して Undo を指示すると、ノードの以前の名前(例では Button)に戻りました。
※ノードの選択を一度解除してからでも、同じノードを対象に Undo されました。
これは、 add_undo_property 関数で、そのノードに以前の名前(例では Button)を設定する手続きを登録したためです。

名前が戻った状態で Ctrl + Y キーで Redo (やり直し)を指示すると、ツールメニューを選択したときと同様に、選択中のノードがの名前が Piyo に変わりました。
※ノードの選択を一度解除してからでも、同じノードを対象に Redo されました。

出力ボトムパネルにもアクションの実行、 Undo, Redo を行った履歴が表示されています。
Rename Node Piyo
シーン元に戻す: Rename Node Piyo
シーンやり直す: Rename Node Piyo
まとめ
今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、 EditorPlugin クラスを用いて追加したツールメニューアイテムで、独自のエディタ拡張機能を実行した後に、EditorUndoRedoManager を用いて Undo, Redo でそのアクションを行う前に戻したり、再びやり直したりする実装例を紹介しました。
参照サイト Thank You!
- Godot Engine – Free and open source 2D and 3D game engine
- プラグインの作成 — Godot Engine (4.x)の日本語のドキュメント
- EditorPlugin — Godot Engine (4.3)の日本語のドキュメント
- EditorUndoRedoManager — Godot Engine (4.3) documentation in English
記事一覧 → Compota-Soft-Press
コメント