フリーランスプログラマーのsatoです。
さっそくですが今回は「Destroy関数」について学んでいきましょう。
「Destroy(デストロイ)」と聞けばなんとなく、何をする関数かわかりますよね。
そのままの意味で、オブジェクトを削除してくれる関数です。
この関数をマスターすれば、自在にオブジェクトを消すことができます。
生成と対になって大切な部分ですね!
また削除は、プログラマーにとって非常に重要かつデリケートな部分です。
少しでも破棄するタイミングを間違えれば、想定外の不具合が発生してしまうでしょう。
そうならないためにも、きっちり「Destroy関数」について学びましょう!
また削除と対となる「生成」に関する記事もありますので、よければ合わせて読んでみてください。
Destroy関数とは?
それでは早速見ていきましょうか。
まずはリファレンスから見ていきましょう。
リファレンスの説明文を抜粋して載せておきます。
ゲームオブジェクトやコンポーネント、アセットを削除します
オブジェクトの obj を破壊します。 obj は Component の場合、GameObjectからコンポーネントを削除し、破壊します。 obj が GameObject の場合、GameObject ならびにすべてのコンポーネント、GameObject の子であるすべてのオブジェクトを破壊します。 オブジェクトの破壊は、現在のフレームのアップデート(Update)処理後に行われますが、常にレンダリング前に実行されます。
参照元:https://docs.unity3d.com/ScriptReference/Object.Destroy.html
重要な部分を、まとめてみましょうか。
①Componentを引数に渡した場合、渡したComponentを破棄してくれる。
②GameObjectを引数に渡した場合、渡したGameObjectと所持している「Component」・「親子関係の子」全てを破棄してくれる。
重要な部分としてはこのあたりでしょう。
つまりDestroy関数を使えば「Component」や「GameObject」を破棄できるということですね!
Destroy関数を使用してみる
GameObjectを削除してみよう!
では実際にDestroy関数を使用して削除してみましょう!
まずはスクリプトを紐付けたオブジェクト自身を破棄する場合です。
自身を削除してみる!
まずはシンプルにCubeオブジェクトを用意します。
そして以下のスクリプトを作成し、Cubeオブジェクトに追加します。
public class DeleteTest : MonoBehaviour { void Update () { // すぐに自分を削除 Destroy (this.gameObject); } }
非常に簡単で、一行記述しただけですね!
実行してみましょう。
ちゃんとオブジェクトが削除されました!
たったこれだけで自身を破棄することができます!
他のGameObjectを削除してみる!
もちろん自身以外のGameObjectの削除も可能です。
以下の例では、DeleteTargetObjという名前のオブジェクトを取得して、削除する例です。
public class DeleteTest : MonoBehaviour { void Update () { //DeleteTargetObj という名前のオブジェクトを取得 GameObject obj = GameObject.Find ("DeleteTargetObj"); // 指定したオブジェクトを削除 Destroy (obj); } }
とても簡単ですね!
コンポーネントも削除してみよう!
次にコンポーネントも削除してみましょうか。
こちらも非常に簡単で、取得してDestroy関数に渡すだけで破棄が行えます。
public class DeleteTest : MonoBehaviour { void Update () { //BoxColliderコンポーネントを取得 BoxCollider component = this.gameObject.GetComponent<BoxCollider>(); // 指定したコンポーネントを削除 Destroy (component); } }
第二引数をつけると…?
リファレンスを見た人ならわかると思いますが、実はDestroy関数には第二引数があります。
public static void Destroy(Object obj, float t = 0.0F);
第一引数(obj)・・・破壊するオブジェクト
第二引数(t)・・・オブジェクトを破壊するまでのディレイ時間(秒)
つまり第二引数に数字を送れば「数秒後にオブジェクトを削除!」なんて処理が非常に簡単にかけるわけですね!
例えば関数を使用してから5秒後に削除して欲しい場合は、以下のようにしましょう!
public class DeleteTest : MonoBehaviour { void Update () { // 5秒後に自分を削除 Destroy (this.gameObject, 5.0f); } }
よくある問題の解決方法!
ここまでで、Destroy関数の使い方は理解できたかと思います。
そこでここから先はより使いこなすために、よくある問題の解決方法を載せておきます。
オブジェクトが消えない!
自身を削除しようとして、以下のようにthisを指定してしまうという間違いがよくあります。
// 自分を削除 Destroy (this);
しかしこれではオブジェクトは消えないんです!
その理由は「this」が指しているのは「このスクリプト自体のコンポーネント」だからです。
これでは、スクリプトコンポーネントの削除しか行えません。
// 自分を削除 Destroy (this.gameobject);
gameobjectを削除したい場合は、きっちり「this.gameobject」を指定しましょう。
子オブジェクトの全削除
自身についている、すべての子オブジェクトを破棄したい場合は、以下のようにループで取得して破棄すると便利です。
// 子オブジェクトをループして取得 foreach ( Transform child in this.transform ) { // 一つずつ破棄する Destroy(child.gameObject); }
カメラから出たオブジェクトは削除
手っ取り早いオブジェクトの削除判断として、カメラから映らなくなったら削除するという方法があります。
以下の説明に出てくる「OnBecameInvisible関数」は、オブジェクトがすべてのカメラに映らなくなったときに呼び出される関数です。
それを利用し、オブジェクトの削除を行ってみましょう。
public class DeleteTest : MonoBehaviour { // カメラに写っていないときに呼ばれる関数 void OnBecameInvisible (){ GameObject.Destroy(this.gameObject); } }
Update関数と同じように、書いておけば、自身がすべてのカメラに映らなくなったときに勝手に呼ばれてくれます。
とても便利ですね!
たったこれだけの処理を追加すれば、余分なオブジェクトの削除機能として成り立ちえます。
ただしこの処理には一点問題があります。
ゲーム画面上のすべてのカメラから映らなくなったとしても、Unityエディタ上のScene画面やPreview画面にオブジェクトが表示されていると、この関数は呼ばれないのです。
①Scene画面
②Preview画面
実はこれらの画面を映すためにUnityエディタ上では、開発の画面表示のために「SceneCamera」や「Preview Camera」というカメラがこっそり回っているからです。
そのカメラたちに写っていると判定されてしまうということです。
リリース時は問題ありませんが、開発中はこのことに気をつけましょう。
まとめ
今回は非常に簡単にですが、オブジェクトの破棄方法を学びました。
オブジェクトの生成と削除は、Unityにとって重要な項目です。
また生成に関する記事もありますので、よければ合わせて読んでみてください。
ぜひ深く学んでみてください。