##Editor上でDebugしたい!
いちいちプレイ押してDebugするの面倒だったので調べました。
Editor上でパラメーターいじりながら調整する状態が理想形です。
今回はコルーチンを使うので難しいのかな~と思いましたが
uniRxを使うといけるという記事を目にしたので試しました。
##プレイモード時に呼び出されるコード
過去に書いたクソコードを再利用しました。
アタッチしたオブジェクトが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
}
2019/04/22 追記
##ボタンはEditor上だけで動かしたい
プレイモード中でもEditor上のボタンが反応してしまう状態だったので
EditorApplication.isPlaying
を書き加えて防ぎました。
if (GUILayout.Button("Test") && EditorApplication.isPlaying == false)
{
//押下時の処理
}
EditorApplication.isPlaying
はEditorがプレイモード中かどうかを判定してbool値を返します。
もう少し便利にしました→続き