0
2

More than 3 years have passed since last update.

[Unity初心者Tips]FindとGetComponentを実行しエラーにどこから呼び出されたかを出す便利メソッド

Last updated at Posted at 2020-06-27

なにをやるのか

Unityで、FindしたやつからGetComponentするという処理は、プログラムの設計によってシングルトンでやってないやつだとよくやります。それの便利版です。説明要らない方は最後へジャンプ。

GameObject gameObject = GameObject.Find("HOGEgo");
HogeComponent hogeComponent = gameObject.GetComponent<HogeComponent>();

親切にエラーを出してあげる

この時、それぞれでnullの可能性があるので、その場合にはエラーを吐いた方がうるさいゲームデザイナーの相手をしなくていい親切に何がおかしいか判った方が効率が好いので、以下のコードになります。

HogeComponent hogeComponent;
GameObject gameObject = GameObject.Find("HOGEgo");
if(gameObject == null){
  Debug.LogError("HOGEgo is not found");
}
else{
  hogeComponent = gameObject.GetComponent<HogeComponent>();
  if(gameObject == null){
    Debug.LogError("HogeComponent is not found");
  }
}

共用できるclassのメソッドにする

折角なので、適当なclassで何処でも使えるようにジェネリック化したstaticのメソッドにしましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CommonTools
{
    public class Tools : MonoBehaviour
    {
        public static T GetComponentInObject<T>(string objectName)
        {
            T c = default(T);
            GameObject gameObject = GameObject.Find(objectName);
            if (gameObject == null) {
                Debug.LogError(objectName + " is not found");
            }
            else {
                c = gameObject.GetComponent<T>();
                if (hogeComponent == null) {
                    Debug.LogError( nameof(T)+ " is not found");
                }
            }
            return c;
        }
    }
}

まあまあ良い感じですね!ここまではありがちです。

どこでやったか判るようにする

上のままでも問題ないんですけど、色々なところから呼び出されるのでエラーを見ても呼び出し元が判らないと修正に困るという問題があります。
うるさいゲームデザイナーの相手をしなくていい親切に何がおかしいか判った方が効率が好いので、ここで呼び出し元が判るようにします。それには以下の仕組みを使います。

呼び出し元はstackから辿れる

アセンブラの知識がある方はご存知の通り、メソッドの呼び出し毎に戻りアドレスがpushされてstackに格納されて積まれます。そこを辿れば、どこから呼び出されているのか判るわけです。
参考:StackFrame クラス
https://docs.microsoft.com/ja-jp/dotnet/api/system.diagnostics.stackframe?view=netcore-3.1

リフレクションで名前を取得する

C#のリフレクションを利用すると、呼び出し元の名前が取得できます。
参考:MemberInfo.ReflectedType プロパティ
https://docs.microsoft.com/ja-jp/dotnet/api/system.reflection.memberinfo.reflectedtype?view=netcore-3.1

エラーで呼び出し元を出す完成版

上記を組み合わせてエラーのためのメソッドをFindGetComponentで共有化した完成例がこちらです。
https://gist.github.com/JunShimura/866cfe8736e4b40f35bf50113748cdd0

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CommonTools
{
    public class Tools : MonoBehaviour
    {
        public static T GetComponentInObject<T>(string objectName)
        {
            T c = default(T);
            GameObject go = GameObject.Find(objectName);
            if (go == null) {
                LogError(objectName);
            }
            else {
                c = go.GetComponent<T>();
                if (c == null) {
                    LogError(objectName + "." + nameof(T));
                }
            }
            return c;
        }
        static private void LogError(string s)
        {
            // StackFrameクラスでstackを2階層戻る
            System.Diagnostics.StackFrame objStackFrame = new System.Diagnostics.StackFrame(2);
            string methodName = objStackFrame.GetMethod().Name;
            Debug.LogError(s + " is not found at "
                + objStackFrame.GetMethod().ReflectedType.FullName
                + "." + objStackFrame.GetMethod().Name);
        }

    }

}

こうすると、

class GameDirector{
    void Start()
    {
        // hpゲージを取得
        hpGaugeImage = Tools.GetComponentInObject<Image>("hogeGauge");

このようなエラーになります。
image.png

うるさいゲームデザイナーの相手をしなくていい親切に何がおかしいか判った方が効率が好いですね!

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2