|
Unity内置了两个类:Editor和EditorWindow。其中Editor主要负责某个GameObject在Scene视图下的UI显示,EditorWindow主要生成一个Window作为插件功能使用。
Editor
使用Editor功能需要一个脚本如TestTool.cs继承MonoBehavior,然后使用TestEditor继承Editor来实现其功能。

需要在TestEditor上添加关键字CustomEditor来表明是对应于哪个脚本,当TestTool.cs挂载的GameObject被选中时TestEditor就会执行。?TestEditor需要放在名为Editor的目录下,路径无关。
TestEditor可以重新实现OnSceneGUI和OnInspectorGUI来绘制自己的GUI。
1 OnSceneGUI
在OnSceneGUI函数是当GameObject被选中每帧执行的。当Scene窗口的Gizmos关闭不执行。
可以获取Event事件,不过这个事件需要在当前挂载TestTool.cs的GameObject被选中时才能接收到。
[CustomEditor(typeof(TestTool))]
public class TestEditor : Editor
{
private void OnSceneGUI()
{
Event e = Event.current;
if(e.isKey)
{
if(e.type == EventType.KeyDown)
{
Debug.Log("YES");
}
}
}
}
在OnSceneGUI函数中可以重新绘制GUI,使用Handle获取相关信息,绘制SceneGUI可以使用GUILayout接口:
string testValue = "";
private void OnSceneGUI()
{
TestTool tt = target as TestTool;
Vector3 pos = tt.gameObject.transform.position;
Handles.Label(pos, "pos is :" + pos.ToString());
Handles.color = Color.green;
Handles.DrawLine(pos, pos+ Vector3.up);
GUILayout.BeginArea(new Rect(100, 100, 100, 100));
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("Test Tool");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
testValue = GUILayout.TextField(testValue);
GUILayout.EndArea();
}

2?OnInspectorGUI
可以使用GUILayout和EditorGUILayout来重新绘制在Inspector面板上的GUI,当这个函数被重写时,之前的公有变量等都不会在Inspector面板上显示了。
public override void OnInspectorGUI()
{
TestTool tt = target as TestTool;
GUILayout.Button(tt.nameStr);
tt.testValue = EditorGUILayout.IntField("height", tt.testValue);
}

?3 执行关键字
?如果不在OnSceneGUI调用TestTool.cs中的函数,那么TestTool只能在运行的时候执行,但是可以添加ExecuteInEditMode 的Attribute让其在预览时执行Awake/Update/Start等内置函数。
[ExecuteInEditMode]
public class TestTool : MonoBehaviour
{
public string nameStr = "TestBtn";
public int testValue = 0;
// Update is called once per frame
void Update()
{
testValue += 1;
testValue %= 10;
}
}

?添加ExecuteAlways的Attribute可以在运行的时候也执行内置函数。
运行自己的函数可以添加代理实现:
private void OnEnable()
{
EditorApplication.update += MyUpdate;
}
private void OnDisable()
{
EditorApplication.update -= MyUpdate;
}
// Update is called once per frame
void MyUpdate()
{
testValue += 1;
testValue %= 10;
}
EditorWindow
首先需要建立一个Window,先继承EditorWindow,再实现一个static函数创建Window:
public class TestWindow : EditorWindow
{
[MenuItem("Tools/testWindow")]
static void CreateWindow()
{
TestWindow te = GetWindow<TestWindow>(false, "TestWindow");
te.Show();
te.autoRepaintOnSceneChange = true;
}
}
创建Window时可以设置OnGUI在SceneChange时刷新:
te.autoRepaintOnSceneChange = true;

?MenuItem是菜单路径,可自定义。
然后可以实现OnGUI方法,这样可以绘制我们想要的UI组件,OnGUI的绘制不一定是Update的速度,可能快可能慢,而且只有在Window为焦点时才比较快执行:
private void OnGUI()
{
var rect = EditorGUILayout.BeginVertical();
GUI.color = Color.white;
GUI.Box(rect, GUIContent.none);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("Test Window");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
EditorGUILayout.LabelField("当前状态显示");
GUILayout.BeginHorizontal();
GUILayout.Space(40);
isToggle = GUILayout.Toggle(isToggle, " 测试Toggle");
GUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}

?创建Window时
?当自定义的Window打开后会一直执行Update函数,可以在调用Repaint,这样就可以加快调用OnGUI了,性能比较差:
private void Update()
{
Repaint();
}
可以使用SceneView添加代理函数来获取键盘等事件,不过必须在Scene视图为焦点时才会调用:
private void OnEnable()
{
SceneView.duringSceneGui += GetEvent;
}
private void OnDisable()
{
SceneView.duringSceneGui -= GetEvent;
}
private void GetEvent(SceneView sceneView)
{
Event e = Event.current;
if (e.isKey)
{
Debug.Log("Key Event");
}
}
如果Event在OnScene下获取则只有在Window为焦点时才会捕获到该事件。目前没有查到全局事件怎么捕获,即不在Scene视图下也能捕获到Event的方法。
上面获取的会把鼠标左键事件吃掉,换成beforeSceneGUI
private void OnEnable()
{
SceneView.beforeSceneGui += GetEvent;
//SceneView.duringSceneGui += GetEvent;
}
private void OnDisable()
{
SceneView.beforeSceneGui -= GetEvent;
//SceneView.duringSceneGui -= GetEvent;
}
|