Godotのノードの消し方(C#)
ゲームエンジンGodotを使っていると、ノードを画面から非表示にする方法がいくつもあることに気づくはずです。例えば、以下のようなものがあります。
-
Node.Free
メソッドを呼び出す。 -
Node.QueueFree
メソッドを呼び出す。 -
Node.CallDeferred("free")
を呼び出す。 -
Node.RemoveChild
メソッドを呼び出す。 -
Node.Dispose
メソッドを呼び出す。
私たちがノードを削除しようと思ったとき、一体どれを呼び出す必要があるのでしょうか?
結論
- ノードを画面から消し、二度と使わない場合、
QueueFree
メソッドを使います。 - ノードを画面から消すが、後でまた表示する場合、
RemoveChild
メソッドを使います。
解説
RemoveChild
RemoveChild
メソッドでノードをノードツリーから取り除くと、画面に表示されなくなるので、ノードを削除できたように見えるかもしれません。しかしこうして非表示にしたノードは、改めて AddChild
メソッドで追加するとまた表示することができますし、ノードのために確保されているメモリは解放されません。
ノードのために確保されているメモリを開放するには、 RemoveChild
ではなく Free
, QueueFree
を呼び出す必要があります。一応、 RemoveChild
と Free
, QueueFree
を両方呼んでも問題ありません。
Free, QueueFree, CallDeferred("free")
Free
メソッドを呼ぶと、ノードを削除し、二度と使用できない状態にします。もし使用しようとしたならば、 ObjectDisposedException
の例外が発生します。
しかし、 Free
が呼ばれた瞬間から決してノードにアクセスしないよう保証するのは難しく、多くの場合は、ノードが二度と使われないと確約できるのは1フレーム後からと考えて設計します。 QueueFree
メソッドを使えば、フレームの最後にノードを削除するので、1フレームの間は誤ってノードにアクセスしようとしても安全です。
一応、 Node.CallDeferred("free")
という呼び出しをすることでもノードを削除できます。これはフレームの最後に free
を呼び出すという意味で、 QueueFree
メソッドを呼ぶこととほとんど一緒です。
ただし、このスレッド によると、 CallDeferred
は GodotObject
クラスのメンバーであるため、ノードでないものに対しても呼ぶことができるそうです。
Dispose
C# 言語で開発している場合、GDScript とは違って Node.Dispose
メソッドがあります。
C# で動作しているとき、GodotのオブジェクトはC#用オブジェクトとネイティブ用オブジェクトが1対1に紐づいて動作しています。 Dispose
メソッドは、C#用オブジェクトの部分を使用できなくするためのメソッドです。
Dispose
を呼んでも、ノードは画面から非表示にはなりません。しかし、そのノードに対して AddChild
を呼ぶなどの操作は二度とできなくなります。 QueueFree
もできなくなるので、ノードは画面に残り続けます。
Dispose
メソッドを呼ぶ必要のある場面が果たしてあるのかは、ぼくには分かりませんでした。
参考
Difference between call_deferred("free") and queue_free?
what is difference queue_free and remove_child?what is queue?
Discussion