Buravo46's Note

学んだ事を書いていくブログです。

【Unity】Interfaceの実装をしたComponentの取得

経緯

Interfaceの実装をしたコンポーネントにすれば、コンポーネントの差し替えが簡単になるということを知り、何故簡単になるのか中々想像が付かなかったので実際に試してみることにしました。

利用場面

f:id:buravo46:20150107210107p:plain

上の画像のようにコンポーネントを付け替えても、制御するコンポーネントを一切弄らずにコンポーネントを取得したい場合などで利用することができます。

方法

  1. 付け替えるコンポーネントの共通する部分を取り出してインターフェイスにします。
  2. 付け替えるコンポーネントに共通するインターフェイスを実装します。
  3. GetComponent関数などでコンポーネントの取得を行う際、引数に共通するインターフェイスを渡します。

上記の手順で、コンポーネントを付け替えても問題なく取得することが出来ます。

実装

具体的な実装内容が下記となっています。

using UnityEngine;
using System.Collections;
/*===============================================================*/
/**
* モーションインターフェイス
* 2015年1月6日 Buravo
*/ 
public interface IMotion
{
    /*===============================================================*/
    /**
    * @brief モーションを開始する関数
    */
    void StartMotion ();
    /*===============================================================*/
}
/*===============================================================*/

これは共通するインターフェイスです。

動きという共通する部分を取り出してインターフェイスにしています。

using UnityEngine;
using System.Collections;
/*===============================================================*/
/**
* 直線モーション
* 2015年1月6日 Buravo
*/ 
public class StraightMotion : MonoBehaviour , IMotion
{
    /*===============================================================*/
    /**
    * @brief モーションを開始する関数
    */
    public void StartMotion ()
    {
        Debug.Log("StraightMotion");
    }
    /*===============================================================*/
}
/*===============================================================*/

共通するインターフェイスを実装したコンポーネントです。

これは前進するコンポーネントとして扱っています。

using UnityEngine;
using System.Collections;
/*===============================================================*/
/**
* 円運動モーション
* 2015年1月6日 Buravo
*/ 
public class CircleMotion : MonoBehaviour , IMotion
{
    /*===============================================================*/
    /**
    * @brief モーションを開始する関数
    */
    public void StartMotion ()
    {
        Debug.Log("CircleMotion");
    }
    /*===============================================================*/
}
/*===============================================================*/

共通するインターフェイスを実装したコンポーネントです。

これは円運動するコンポーネントとして扱っています。

using UnityEngine;
using System.Collections;
/*===============================================================*/
/**
* 制御するスクリプトコンポーネント
* 2015年1月6日 Buravo
*/
public class EnemyController : MonoBehaviour 
{
    #region パブリック変数
    /*===============================================================*/
    /**
    * @brief モーション開始を判断するフラグ.
    */ 
    public bool isStartMotion = false;
    /**
    * @brief 全てのモーション開始を判断するフラグ.
    */
    public bool isStartAllMotion = false;
    /*===============================================================*/
    #endregion

    /*===============================================================*/
    /**
    * @brief スクリプトがロードされたとき、またはインスペクタ上で値が変更されたときに呼び出しされる関数
    */
    void OnValidate ()
    {
        if (isStartMotion)
        {
            StartMotion();
        }
        else if (isStartAllMotion)
        {
            StartAllMotion();
        }
    }
    /*===============================================================*/

    /*===============================================================*/
    /**
    * @brief モーション開始
    */
    void StartMotion ()
    {
        // モーションインターフェイスを持つスクリプトコンポーネントを取得.
        IMotion motion = GetComponent(typeof(IMotion)) as IMotion;
        // モーション開始.
        motion.StartMotion();
    }
    /*===============================================================*/

    /*===============================================================*/
    /**
    * @brief 全てのモーション開始.
    */
    void StartAllMotion ()
    {
        // モーションインターフェイスを持つ全てのスクリプトコンポーネントをComponent型の配列で取得.
        Component[] motions = GetComponents(typeof(IMotion));
        // 配列の要素をIMotion型として取り出して処理.
        foreach (IMotion motion in motions)
        {
            // モーション開始.
            motion.StartMotion();
        }
    }
    /*===============================================================*/
}
/*===============================================================*/

これは敵を制御するスクリプトコンポーネントです。

インスペクタで弄れるようにパブリックな変数としてフラグを用意しています。

このフラグをtrueにすることによって取得できているかを確認することが出来ます。

MonoBehaviour.OnValidate関数内では、実際にコンポーネントを差し替えても取得して使用できることを確認できるようにしています。

StartMotion関数やStartAllMotion関数内でコンポーネントを取得し関数を呼び出しています。

まとめ

Interfaceの実装をコンポーネントにすれば、コンポーネントを付け替えても同じように取得することが出来ました。

これでもう一々コンポーネントを付け替えたからってGetComponentの引数を変更せずに済む訳ですね。

参考サイト

いろいろガンガンいこうぜ。体も大事に - GetComponentメソッドについて

Christopher Jones, Games Development - Unity, GetComponent < T > and Interfaces

++C++; // 未確認飛行 C - インターフェース

Unityスクリプトリファレンス - GameObject

Unityスクリプトリファレンス - MonoBehaviour