LoginSignup
1

More than 3 years have passed since last update.

【Unity(C#)】UniRxを使ってEditor上でDebugしてみた

Last updated at Posted at 2019-04-19

Editor上でDebugしたい!

いちいちプレイ押してDebugするの面倒だったので調べました。

Editor上でパラメーターいじりながら調整する状態が理想形です。

今回はコルーチンを使うので難しいのかな~と思いましたが
uniRxを使うといけるという記事を目にしたので試しました。

プレイモード時に呼び出されるコード

過去に書いたクソコードを再利用しました。
アタッチしたオブジェクトがTargetに設定したオブジェクトに向かって進みます。

アタッチしたオブジェクトがTargetオブジェクトに向かう
    [SerializeField]
    GameObject targetObj;

    Coroutine coroutine;

    float x_Abs;
    float y_Abs;
    float z_Abs;

    [SerializeField,Range(1,100)]
    float speedParameter = 10;

     void Update()
    {
        x_Abs = Mathf.Abs(this.gameObject.transform.position.x - targetObj.transform.position.x);
        y_Abs = Mathf.Abs(this.gameObject.transform.position.y - targetObj.transform.position.y);
        z_Abs = Mathf.Abs(this.gameObject.transform.position.z - targetObj.transform.position.z);
    }

    void Move()
    {
        coroutine = StartCoroutine(MoveCoroutine());  
    }

    IEnumerator MoveCoroutine()
    {
        float speed = speedParameter * Time.deltaTime;

        while (x_Abs > 0 || y_Abs > 0 || z_Abs > 0)
        {
            this.gameObject.transform.position = Vector3.MoveTowards(this.gameObject.transform.position, targetObj.transform.position, speed);
            yield return null;
        }

         StopCoroutine(coroutine);
         coroutine = null;

    }

このコードをEditor上で動かすのが今回のゴールです。

GUILayout.Button

Editor上でDebugする方法として、
ボタンを押したら、メソッドが実行される仕組みを作ります。

その仕組みに必要なのがGUILayout.Buttonです。

使い方は、Editor拡張コードの中に組み込めばOKです。

#if UNITY_EDITOR
    [CustomEditor(typeof(拡張したいクラスの名前))]
    public class Debug : Editor
    {

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            EditorDebugTest _RootClass = target as 拡張したいクラスの名前;

            //少しスペースを空ける
            EditorGUILayout.Space();

            // 押下時に実行したい処理
            if (GUILayout.Button("Inspectorに表示されるボタン名"))
            {
                _RootClass.実行したいメソッド;
            }
        }
    }
#endif

Observable.FromCoroutine

私もまだ学び始めてばかりなので、
"これを書いたらこう動く"程度でしか理解していません。

とにかく、このFromCoroutineというのを使えば、
コルーチンを動かした上で
コルーチンの終わりを監視することができるようです。

しかも、StartCoroutineを必要としないのでEditor上でも動かすことができます

これを先程のGUILayout.Buttonと組み合わせます。

#if UNITY_EDITOR
    [CustomEditor(typeof(拡張したいクラスの名前))]
    public class Debug : Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            EditorDebugTest _RootClass = target as 拡張したいクラスの名前;

            //少しスペースを空ける
            EditorGUILayout.Space();

            // 押下時に実行したい処理
            if (GUILayout.Button("Inspectorに表示されるボタン名"))
            {
               Observable.FromCoroutine(_RootClass.MoveCoroutine).Subscribe(_ =>
               {
                  _RootClass.実行したいメソッド;
               });
            }
        }
    }
#endif

これでEditor上でコルーチンを呼び出すことに成功しました。

ただし、このままではコルーチンが実行された後に
オブジェクトが移動したままになってしまいます。

それだとDebugとして軽く調整するには不十分なので
動き終わったらもとの位置に戻るコードを加えます。

もとの位置に戻るコードはFromCoroutine
コルーチンの終わりを監視しているので、その中に書いてしまえば終了です。

最終的なコード

てすと
using System.Collections;
using UnityEditor;
using UnityEngine;
using UniRx;

public class EditorDebugTest : MonoBehaviour
{
    [SerializeField]
    GameObject targetObj;

    Coroutine coroutine;

    Vector3 originalPosition;

    float x_Abs;
    float y_Abs;
    float z_Abs;

    [SerializeField,Range(1,100)]
    float speedParameter = 10;

    bool isCoroutineRun;

    void Move()
    {
        coroutine = StartCoroutine(MoveCoroutine());  
    }

    IEnumerator MoveCoroutine()
    {
        float speed = speedParameter * Time.deltaTime;
        originalPosition = this.gameObject.transform.position;

        x_Abs = Mathf.Abs(this.gameObject.transform.position.x - targetObj.transform.position.x);
        y_Abs = Mathf.Abs(this.gameObject.transform.position.y - targetObj.transform.position.y);
        z_Abs = Mathf.Abs(this.gameObject.transform.position.z - targetObj.transform.position.z);
        while (x_Abs > 0 || y_Abs > 0 || z_Abs > 0)
        {
            x_Abs = Mathf.Abs(this.gameObject.transform.position.x - targetObj.transform.position.x);
            y_Abs = Mathf.Abs(this.gameObject.transform.position.y - targetObj.transform.position.y);
            z_Abs = Mathf.Abs(this.gameObject.transform.position.z - targetObj.transform.position.z);
            this.gameObject.transform.position = Vector3.MoveTowards(this.gameObject.transform.position, targetObj.transform.position, speed);
            yield return null;
        }

        if (coroutine != null)
        {
            StopCoroutine(coroutine);
            coroutine = null;

        }
    }

     void ResetPosition()
    {
        this.gameObject.transform.position = originalPosition;
    }

#if UNITY_EDITOR
    [CustomEditor(typeof(EditorDebugTest))]
    public class Debug : Editor
    {

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            EditorDebugTest _RootClass = target as EditorDebugTest;

            EditorGUILayout.Space();

            // 押下時に実行したい処理
            if (GUILayout.Button("Test") && EditorApplication.isPlaying == false)
            {
                if (_RootClass.isCoroutineRun == false)
                {
                    _RootClass.isCoroutineRun = true;

                    Observable.FromCoroutine(_RootClass.MoveCoroutine).Subscribe(_ =>
                    {
                        _RootClass.isCoroutineRun = false;
                        _RootClass.ResetPosition();
                    });
                }
            }
        }
    }
#endif

}

イメージ通りいけました。
a.gif


2019/04/22 追記

ボタンはEditor上だけで動かしたい

プレイモード中でもEditor上のボタンが反応してしまう状態だったので
EditorApplication.isPlayingを書き加えて防ぎました。


if (GUILayout.Button("Test") && EditorApplication.isPlaying == false)
{
  //押下時の処理
}

EditorApplication.isPlayingはEditorがプレイモード中かどうかを判定してbool値を返します。

もう少し便利にしました→続き

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
1