🗑️

Godotのノードの消し方(C#)

2023/10/23に公開

ゲームエンジンGodotを使っていると、ノードを画面から非表示にする方法がいくつもあることに気づくはずです。例えば、以下のようなものがあります。

  • Node.Free メソッドを呼び出す。
  • Node.QueueFree メソッドを呼び出す。
  • Node.CallDeferred("free") を呼び出す。
  • Node.RemoveChild メソッドを呼び出す。
  • Node.Dispose メソッドを呼び出す。

私たちがノードを削除しようと思ったとき、一体どれを呼び出す必要があるのでしょうか?

結論

  • ノードを画面から消し、二度と使わない場合、 QueueFree メソッドを使います。
  • ノードを画面から消すが、後でまた表示する場合、 RemoveChild メソッドを使います。

解説

RemoveChild

RemoveChild メソッドでノードをノードツリーから取り除くと、画面に表示されなくなるので、ノードを削除できたように見えるかもしれません。しかしこうして非表示にしたノードは、改めて AddChild メソッドで追加するとまた表示することができますし、ノードのために確保されているメモリは解放されません。

ノードのために確保されているメモリを開放するには、 RemoveChild ではなく Free, QueueFree を呼び出す必要があります。一応、 RemoveChildFree, QueueFree を両方呼んでも問題ありません。

Free, QueueFree, CallDeferred("free")

Free メソッドを呼ぶと、ノードを削除し、二度と使用できない状態にします。もし使用しようとしたならば、 ObjectDisposedException の例外が発生します。

しかし、 Free が呼ばれた瞬間から決してノードにアクセスしないよう保証するのは難しく、多くの場合は、ノードが二度と使われないと確約できるのは1フレーム後からと考えて設計します。 QueueFree メソッドを使えば、フレームの最後にノードを削除するので、1フレームの間は誤ってノードにアクセスしようとしても安全です。

一応、 Node.CallDeferred("free") という呼び出しをすることでもノードを削除できます。これはフレームの最後に free を呼び出すという意味で、 QueueFree メソッドを呼ぶこととほとんど一緒です。

ただし、このスレッド によると、 CallDeferredGodotObject クラスのメンバーであるため、ノードでないものに対しても呼ぶことができるそうです。

Dispose

C# 言語で開発している場合、GDScript とは違って Node.Dispose メソッドがあります。

C# で動作しているとき、GodotのオブジェクトはC#用オブジェクトとネイティブ用オブジェクトが1対1に紐づいて動作しています。 Dispose メソッドは、C#用オブジェクトの部分を使用できなくするためのメソッドです。

Dispose を呼んでも、ノードは画面から非表示にはなりません。しかし、そのノードに対して AddChild を呼ぶなどの操作は二度とできなくなります。 QueueFree もできなくなるので、ノードは画面に残り続けます。

Dispose メソッドを呼ぶ必要のある場面が果たしてあるのかは、ぼくには分かりませんでした。

参考

Difference between call_deferred("free") and queue_free?

IDisposable & Free() in C#

what is difference queue_free and remove_child?what is queue?

Discussion