【Unity】スクリプトからコンポーネントを追加・削除・オンオフする方法

コンポーネントの追加・削除 Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「スクリプトからコンポーネントを追加したい!」

「アタッチしたコンポーネントをゲーム内で削除したい!」

というお悩みの方に向けた内容となっています。

Unityでは、コンポーネントをオブジェクトに紐づけてあげることで、そのオブジェクトに対して様々な機能を持たせることができます。

そして、このコンポーネントを紐づけたり外したりする処理は、通常はインスペクターウィンドウから行いますが、ゲーム内の動きのある中で追加したり削除する場合は、スクリプトから記述する必要があります。

例えば、スクリプトからコンポーネントを追加できるAddComponentメソッドや、コンポーネントを削除できるDestroyメソッド、コンポーネントのアクティブ化を切り替えるenabledプロパティなどを使うことで可能になります。

そこで、このページでは、Unityでスクリプトからコンポーネントを追加したり、削除したり、アクティブ状態の切り替えを行う方法についてまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

スクリプトからコンポーネントを追加する方法

まずは、スクリプトからコンポーネントを追加する方法について紹介していきます。

AddComponentメソッドで追加できる

スクリプトからコンポーネントを追加する場合は、AddComponentメソッドを使います。

このAddComponentメソッドは、ゲームオブジェクトに対して、以下のように記述して使います。

GameObject.AddComponent<コンポーネント名>();

また、AddComponentで追加する際に、左辺にそのコンポーネント型の変数を作り代入してあげることで、そのコンポーネントを参照できるようになります。

例えば、以下のようにスクリプトで記述することで、ゲーム実行後にBoxColliderコンポーネントを追加するということができます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        gameObject.AddComponent<BoxCollider>();
    }
}

ゲームの途中でRigidbodyコンポーネントを追加する処理

実際に、Unity上でAddComponentメソッドを使った処理を作ってみます。

以下のように、四角のオブジェクトを複数配置しておき、ゲーム開始後スペースキーを押したら、それぞれのオブジェクトにRigidbodyコンポーネントが追加されるようにしてみます。

空オブジェクトを配置して、以下のスクリプトをアタッチしておきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject[] objects;    // オブジェクトを取得する配列を宣言

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            foreach (GameObject obj in objects)
            {
                obj.AddComponent<Rigidbody>();  // Rigidbodyコンポーネントを追加する処理
            }
        }
    }
}

5行目でゲームオブジェクト用の配列をpublicで作り、インスペクターウィンドウからそれぞれのオブジェクトを入れておきます。

そして、スペースキーを押した場合の中の13行目で、AddComponentメソッドを使ってRigidbodyコンポーネントを追加しています。

なお、今回は複数のオブジェクトがあるので、foreach文を使って繰り返しの処理を作っています。

これでゲームを実行してみると、

スペースキーを押すと、オブジェクトにRigidbodyコンポーネントが追加され、重力により落ちていくのが分かります。

スクリプトからコンポーネントを削除する方法

次に、スクリプトからコンポーネントを削除する方法について紹介していきます。

Destroyメソッドで削除できる

スクリプトからコンポーネントを削除する場合は、Destroyメソッドを使って削除することができます。

このDestroyメソッドは、オブジェクトを破壊する際に使われることが多いですが、コンポーネントを削除するために使うこともできます。

Destroyメソッドでコンポーネントを削除する場合は、以下のように引数にコンポーネントを指定して使います。

Destroy(削除したいコンポーネント);

ただし、削除したいコンポーネントを指定するために、事前にそのコンポーネントをスクリプト内で取得しておく必要があります。

例えば、オブジェクトにRigidbodyコンポーネントが紐づいた状態で、そのコンポーネントを削除したい場合は、

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        Rigidbody rb = GetComponent<Rigidbody>();   // Rigidbodyコンポーネントを取得
        Destroy(rb);    // コンポーネントを削除する処理
    }
}

上記のように、7行目でGetComponentメソッドでコンポーネントを事前に取得して変数に入れておくことで、8行目のDestroyメソッドの引数に指定し削除することができます。

なお、そのスクリプト自体をオブジェクトから外したい場合は、

Destroy(this);

と、thisキーワードを付けて書いてあげることで、指定できます。

ゲームの途中で独自のコンポーネントを削除する処理

実際に、Unity上でDestroyメソッドを使ってコンポーネントを削除する処理を作ってみます。

ここでは、独自で作った2Dオブジェクトの色を変化させるスクリプト(コンポーネント)を作り、オブジェクトに紐づけておき、別のスクリプトでスペースキーを押したらそのコンポーネントを削除するという処理を行います。

まず、オブジェクトの色を変化させるColorChangeというスクリプトを作っていきます。

using UnityEngine;

public class ColorChange : MonoBehaviour
{
    Color startColor = Color.black; // 最初のスタートの色
    Color endColor = Color.yellow;     // 目標となる色
    SpriteRenderer sr;
    int deirection = 1; // 色を変更させる向き
    float delta;    // 時間を計測する変数

    void Start()
    {
        sr = GetComponent<SpriteRenderer>();    // SpriteRendererコンポーネントを取得
        sr.color = startColor;  // スタート時の色を指定
    }

    void Update()
    {
        delta += Time.deltaTime;    // 時間を加算する処理

        if (deirection == 1)
        {
            sr.color = Color.Lerp(startColor, endColor, delta / 2.5f); // 2.5秒かけて黒から赤に変更する処理
            // 赤色になった場合の処理
            if (sr.color == endColor)
            {
                deirection = -1;
                delta = 0;
            }
        }

        if (deirection == -1)
        {
            sr.color = Color.Lerp(endColor, startColor, delta / 2.5f); // 2.5秒かけて赤から黒に変更する処理
            // 黒になった場合の処理
            if (sr.color == startColor)
            {
                deirection = 1;
                delta = 0;
            }
        }
    }
}

23行目でLerpメソッドを使って、オブジェクトの色を黒から黄に徐々に変化する処理を作っています。

また、完全に黄色に変化したら、34行目で今度は黄色から黒色に徐々に変化させる処理を行っています。

そして、directionの変数を作り、この変数の値で処理が繰り返されるように記述しています。

このスクリプトをオブジェクトにアタッチすると、以下のように色が変化するようになります。

次に、このオブジェクトから上記のコンポーネントを削除するためのスクリプトを作っていきます。

空オブジェクトを作成して、以下のスクリプトをアタッチしていきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    public ColorChange colorChange; // ColorChange型の変数を宣言

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Destroy(colorChange);   // ColorChangeコンポーネントを削除する処理
        }
    }
}

5行目でColorChange型の変数をpublicで宣言しておき、インスペクターから先ほどのオブジェクトを指定しておきます。

そして、スペースキーを押した場合の中の11行目で、Destroyメソッドで削除する処理を記述しておきます。

これでゲームを実行してみると、

スペースキーを押すとColorChangeのスクリプトが削除されて、色が変化する処理が止まっているのが分かります。

スクリプトからコンポーネントをオンオフする方法

次に、スクリプトからコンポーネントのアクティブ状態をオンオフする方法について紹介していきます。

enabledプロパティで有効と無効を切り替えられる

スクリプトからコンポーネントのアクティブ状態をオンオフする場合は、enabledプロパティを使って切り替えることができます。

このenabledプロパティは、コンポーネントに対してtrueもしくはfalseの値を使って、アクティブ状態のオンオフを行う処理を行えます。

// コンポーネントをオンにする場合
オンにしたいコンポーネント.enabled = true;

// コンポーネントをオフにする場合
オフにしたいコンポーネント.enabled = false;

なお、先ほどのDestroyメソッドと同じく、事前にコンポーネントを取得しておく必要があります。

例えば、BoxColliderコンポーネントを紐づけているオブジェクトに対して、以下のスクリプトをアタッチしておきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        BoxCollider collider = GetComponent<BoxCollider>();   // BoxColliderコンポーネントを取得
        collider.enabled = false;    // コンポーネントを無効化する処理
    }
}

7行目で、GetComponentメソッドを使って、BoxColliderコンポーネントを取得しています。

そして、8行目でenabledプロパティでfalseに変更する処理を行っています。

これでゲームを実行してみると、

オブジェクトに紐づいているRigidbodyコンポーネントがオフになっているのが分かります。

マウスのクリックでオンオフを切り替える処理

実際に、Unity上でenabledプロパティを使ってコンポーネントのアクティブ状態をオンオフする処理を作ってみます。

ここでは、先ほどDestroyメソッドの際に使ったColorChangeのスクリプトを、複数の2Dオブジェクトに紐づけて配置しておきます。

今回は、それぞれのオブジェクトにBoxCollider2Dコンポーネントを設定しておき、オブジェクトをマウスでクリックしたら、ColorChangeの機能のアクティブ状態が入れ替わるという処理を作ってみます。

まず空オブジェクトを作成して、それぞれのオブジェクトの親オブジェクトになるように配置しておきます。

そして、この親のオブジェクトに以下のスクリプトをアタッチしておきます。

using UnityEngine;

public class ScriptChanger : MonoBehaviour
{
    ColorChange[] colorChanges; // ColorChange型の配列を宣言
    RaycastHit2D hit;

    void Start()
    {
        colorChanges = GetComponentsInChildren<ColorChange>();  // 子オブジェクトのコンポーネントを一括で取得
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);    // カメラからマウスカーソルの位置のRayを作成
            hit = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction);   // Rayで当たったオブジェクト情報を取得
            if (hit.collider != null)
            {
                ComponentChange();
            }
        }
    }

    void ComponentChange()
    {
        foreach (ColorChange col in colorChanges)
        {
            // クリックしたのと同じオブジェクトを探す
            if (col.gameObject == hit.collider.gameObject)
            {
                // 有効の状態の場合
                if (col.isActiveAndEnabled)
                {
                    col.enabled = false;    // コンポーネントをオフにする処理
                }
                // 無効の状態の場合
                else if (!col.isActiveAndEnabled)
                {
                    col.enabled = true;     // コンポーネントをオンにする処理
                }
                break;
            }
        }
    }
}

まず、10行目でGetComponentsInChildrenメソッドを使って、子オブジェクトのColorChangeコンポーネントを一括して取得しておきます。

次に、18行目でPhysics2D.Raycastメソッドを使って、マウスをクリックした位置にあるオブジェクト情報を取得します。

そして、オブジェクトがクリックされている場合は、31行目でそのクリックしたオブジェクトと一致するColorChangeコンポーネントのオブジェクトを検索して、見つかったらenabledプロパティの値を変更するようにしています。

ちなみに、コンポーネントの現在のアクティブ状態を取得するために、isActiveAndEnabledという変数を使っていて、この変数がtrueの場合は有効状態、falseの場合は無効状態となっています。

これでゲームを実行してみると、

マウスでクリックしたオブジェクトは、ColorChangeコンポーネントのステータス状態がオフになるので、色の変更が停止されます。

また、処理が停止しているオブジェクトをもう一度クリックすると、ColorChangeコンポーネントがオンになるので、色の変更処理が再開されます。

まとめ

このページでは、Unityでスクリプトからコンポーネントを追加したり、削除したり、アクティブ状態のオンオフを切り替える方法についてまとめていきましたが、いかがでしたでしょうか?

スクリプトからコンポーネントを追加する場合は、AddComponentメソッドを使うことで、オブジェクトに対してコンポーネントが追加されます。

また、コンポーネントを削除する場合は、事前にそのコンポーネントを取得しておくことで、Destroyメソッドを使って削除できます。

そして、コンポーネントの有効と無効の切り替えは、enabledプロパティを使ってtrueとfalseの値で切り替え処理を作ることができます。

最後までお読みいただきまして、ありがとうございました!

コメント