1. 程式人生 > >Unity 編輯器開發SceneView GUI控制

Unity 編輯器開發SceneView GUI控制

前幾天專案需要就做了個類似於Collider EditCollider的功能

 

下面是我做的效果

基礎程式碼如下:

public class ExportCFGInputWindow : EditorWindow
{
    public static ExportCFGInputWindow instance;
    Vector3 dot1, dot2, dot3, dot4;
  
    void OnEnable() {
        instance = this;
        SceneView.duringSceneGui -= this.OnSceneGUI;
        SceneView.duringSceneGui += this.OnSceneGUI;
        dot1 = new Vector3(0, 0, 0);
        dot2 = new Vector3(0, 0, 1);
        dot3 = new Vector3(1, 0, 1);
        dot4 = new Vector3(1, 0, 0);
        mid1Cor = Color.green;
        mid2Cor = Color.green;
        mid3Cor = Color.green;
        mid4Cor = Color.green;
    }
    void OnDisable() {
        instance = null;
        SceneView.duringSceneGui -= this.OnSceneGUI;
    }

  
    void OnSceneGUI(SceneView sceneView)
    {
        Handles.color = Color.green;
        Handles.DrawAAPolyLine(2, dot1, dot2, dot3, dot4, dot1);
 
    }

}

效果如圖

 

下面是我踩的坑

    先不管先把小綠點畫於是我在OnSceneGui方法裡面插入瞭如下程式碼

void OnSceneGUI(SceneView sceneView)
    {
        Handles.color = Color.green;
        Handles.DrawAAPolyLine(2, dot1, dot2, dot3, dot4, dot1);

         Handles.DotHandleCap(0, new Vector3((dot1.x + dot2.x) * 0.5f, 0, (dot1.z + dot2.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);

      //0.005f * sceneView.size 的作用是讓小綠點無論你把場景放大或者縮小都是一樣大。

Handles.DotHandleCap(0, new Vector3((dot2.x + dot3.x) * 0.5f, 0, (dot2.z + dot3.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint); Handles.DotHandleCap(0, new Vector3((dot3.x + dot4.x) * 0.5f, 0, (dot3.z + dot4.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint); Handles.DotHandleCap(0, new Vector3((dot4.x + dot1.x) * 0.5f, 0, (dot4.z + dot1.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint); }

    這是畫完綠點的樣子

    雖然有了綠點但是沒法控制於是我寫了個方法來監聽滑鼠,這個方法在OnSceneGUI函式中呼叫。具體思路是:綠點的位置知道,只要監聽滑鼠在綠點下按下然後移動滑鼠,我控制綠點兩端的點跟著滑鼠移動就可以完成了。

    但是!萬事都怕但是。出現了一個令我頭大的問題:滑鼠左鍵的EventType.MouseUp事件我監聽不到(這個問題求好心人幫忙解釋一下。)導致我無法停止對相應點的控制,當然滑鼠中鍵和滑鼠右鍵沒有問題,但是滑鼠中鍵和滑鼠右鍵會在編輯器下有其他操作。於是我放棄了這個思路。(這裡程式碼就不上了)

    既然滑鼠不行被逼無奈我就使用了鍵盤控制的方式 ,思路如下:

      4鍵控制上圖最左邊的小綠點,8鍵控制最上面的小綠點,6鍵控制最右面的小綠點,2鍵控制最下面的小綠點。+鍵表示該點向外伸,-鍵表示該點向外內縮。

    下面是程式碼

int ExportDir = 0;//移動方向
void CheckKey()//這個方法在OnSeneGui函式中呼叫 { Event e = Event.current; if (e.type == EventType.KeyDown) { if (e.keyCode == KeyCode.Keypad4) { ExportDir = 4; mid1Cor = Color.red; mid2Cor = Color.green; mid3Cor = Color.green; mid4Cor = Color.green; } if (e.keyCode == KeyCode.Keypad6) { ExportDir = 6; mid1Cor = Color.green; mid2Cor = Color.green; mid3Cor = Color.red; mid4Cor = Color.green; } if (e.keyCode == KeyCode.Keypad2) { ExportDir = 2; mid1Cor = Color.green; mid2Cor = Color.green; mid3Cor = Color.green; mid4Cor = Color.red; } if (e.keyCode == KeyCode.Keypad8) { ExportDir = 8; mid1Cor = Color.green; mid2Cor = Color.red; mid3Cor = Color.green; mid4Cor = Color.green; } if (e.keyCode == KeyCode.KeypadPlus) { //ExportDir = 4; Plus(ExportDir); } if (e.keyCode == KeyCode.KeypadMinus) { //ExportDir = 4; Minus(ExportDir); } } }
  float EditorSpeed = 0.05f; void Plus(int dir) { if (dir == 4) { dot1.x -= EditorSpeed; dot2.x -= EditorSpeed; } else if (dir == 6) { dot3.x += EditorSpeed; dot4.x += EditorSpeed; } else if (dir == 2) { dot1.z -= EditorSpeed; dot4.z -= EditorSpeed; } else if (dir == 8) { dot2.z += EditorSpeed; dot3.z += EditorSpeed; } else { return; } } void Minus(int dir) { if (dir == 4) { dot1.x += EditorSpeed; dot2.x += EditorSpeed; } else if (dir == 6) { dot3.x -= EditorSpeed; dot4.x -= EditorSpeed; } else if (dir == 2) { dot1.z += EditorSpeed; dot4.z += EditorSpeed; } else if (dir == 8) { dot2.z -= EditorSpeed; dot3.z -= EditorSpeed; } else { return; } }

      這樣一來我先按下數字鍵4在按下+鍵最左邊的點就會向左移動了

      為了顯示清楚我還對小綠點顯示顏色左了相應的處理,當選擇哪個點做動作時它就會變紅,程式碼如下

Color    mid1Cor = Color.green;
Color    mid2Cor = Color.green;
Color    mid3Cor = Color.green;
Color    mid4Cor = Color.green;
void OnSceneGUI(SceneView sceneView)
    {
        Handles.color = Color.green;
        Handles.DrawAAPolyLine(2, dot1, dot2, dot3, dot4, dot1);

        
         Handles.color = mid1Cor;
         Handles.DotHandleCap(0, new Vector3((dot1.x + dot2.x) * 0.5f, 0, (dot1.z + dot2.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid2Cor;
         Handles.DotHandleCap(0, new Vector3((dot2.x + dot3.x) * 0.5f, 0, (dot2.z + dot3.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid3Cor;
         Handles.DotHandleCap(0, new Vector3((dot3.x + dot4.x) * 0.5f, 0, (dot3.z + dot4.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid4Cor;
         Handles.DotHandleCap(0, new Vector3((dot4.x + dot1.x) * 0.5f, 0, (dot4.z + dot1.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         CheckKey();
       
    }

    效果如下:

  這個功能也能勉強滿足需求,暫時就這樣了。

  後來有一天,我發現有人這樣用

 Handles.FreeMoveHandle(target.pos,Quaternion.identity,2.0,Vector3.zero,Handles.DrawRectangle);

  Handles類的FreeMoveHandle函式我馬上查了一下API發現

public static Vector3 FreeMoveHandle(Vector3 position, Quaternion rotation, float size, Vector3 snap, DrawCapFunction capFunc);

  最後一個引數是個委託。我一下子就明白改怎麼弄了。程式碼如下

 void OnSceneGUI(SceneView sceneView)
    {
        Handles.color = Color.green;
        Handles.DrawAAPolyLine(2, dot1, dot2, dot3, dot4, dot1);

         float m1px = Handles.FreeMoveHandle(new Vector3((dot1.x + dot2.x) * 0.5f, 0, (dot1.z + dot2.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).x;
         dot1 = new Vector3(m1px, 0, dot1.z);
         dot2 = new Vector3(m1px, 0, dot2.z);

         float m2px = Handles.FreeMoveHandle(new Vector3((dot2.x + dot3.x) * 0.5f, 0, (dot2.z + dot3.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).z;
         dot2 = new Vector3(dot2.x, 0, m2px);
         dot3 = new Vector3(dot3.x, 0, m2px);

         float m3px = Handles.FreeMoveHandle(new Vector3((dot3.x + dot4.x) * 0.5f, 0, (dot3.z + dot4.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).x;
         dot3 = new Vector3(m3px, 0, dot3.z);
         dot4 = new Vector3(m3px, 0, dot4.z);

         float m4px = Handles.FreeMoveHandle(new Vector3((dot4.x + dot1.x) * 0.5f, 0, (dot4.z + dot1.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).z;
         dot4 = new Vector3(dot4.x, 0, m4px);
         dot1 = new Vector3(dot1.x, 0, m4px);

    }

  這樣就達到了我想要的滑鼠控制小綠點的效果。但是鍵盤控制的程式碼我也保留了,因為我覺得這是個教訓,而且在有時候鍵盤控制也蠻方便的。

完整程式碼如下:

public class ExportCFGInputWindow : EditorWindow
{
    public static ExportCFGInputWindow instance;
    Vector3 dot1, dot2, dot3, dot4;
    Color mid1Cor, mid2Cor, mid3Cor, mid4Cor;
    int ExportDir = 0;
    float EditorSpeed = 0.05f;
    void OnEnable() {
        instance = this;
        SceneView.duringSceneGui -= this.OnSceneGUI;
        SceneView.duringSceneGui += this.OnSceneGUI;
        dot1 = new Vector3(0, 0, 0);
        dot2 = new Vector3(0, 0, 1);
        dot3 = new Vector3(1, 0, 1);
        dot4 = new Vector3(1, 0, 0);
        mid1Cor = Color.green;
        mid2Cor = Color.green;
        mid3Cor = Color.green;
        mid4Cor = Color.green;
    }
    void OnDisable() {
        instance = null;
        SceneView.duringSceneGui -= this.OnSceneGUI;
    }

    Vector3 m1, m2, m3, m4;
    void OnSceneGUI(SceneView sceneView)
    {
        Handles.color = Color.green;
        Handles.DrawAAPolyLine(2, dot1, dot2, dot3, dot4, dot1);

         #region 滑鼠控制
         float m1px = Handles.FreeMoveHandle(new Vector3((dot1.x + dot2.x) * 0.5f, 0, (dot1.z + dot2.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).x;
         dot1 = new Vector3(m1px, 0, dot1.z);
         dot2 = new Vector3(m1px, 0, dot2.z);

         float m2px = Handles.FreeMoveHandle(new Vector3((dot2.x + dot3.x) * 0.5f, 0, (dot2.z + dot3.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).z;
         dot2 = new Vector3(dot2.x, 0, m2px);
         dot3 = new Vector3(dot3.x, 0, m2px);

         float m3px = Handles.FreeMoveHandle(new Vector3((dot3.x + dot4.x) * 0.5f, 0, (dot3.z + dot4.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).x;
         dot3 = new Vector3(m3px, 0, dot3.z);
         dot4 = new Vector3(m3px, 0, dot4.z);

         float m4px = Handles.FreeMoveHandle(new Vector3((dot4.x + dot1.x) * 0.5f, 0, (dot4.z + dot1.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, Vector3.zero, Handles.DotCap).z;
         dot4 = new Vector3(dot4.x, 0, m4px);
         dot1 = new Vector3(dot1.x, 0, m4px);
         #endregion

         #region 鍵盤控制
         Handles.color = mid1Cor;
         Handles.DotHandleCap(0, new Vector3((dot1.x + dot2.x) * 0.5f, 0, (dot1.z + dot2.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid2Cor;
         Handles.DotHandleCap(0, new Vector3((dot2.x + dot3.x) * 0.5f, 0, (dot2.z + dot3.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid3Cor;
         Handles.DotHandleCap(0, new Vector3((dot3.x + dot4.x) * 0.5f, 0, (dot3.z + dot4.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         Handles.color = mid4Cor;
         Handles.DotHandleCap(0, new Vector3((dot4.x + dot1.x) * 0.5f, 0, (dot4.z + dot1.z) * 0.5f), Quaternion.identity, 0.005f * sceneView.size, EventType.Repaint);
         CheckKey();
         #endregion
         
    }
   
    void CheckKey()
    {
        Event e = Event.current;
        if (e.type == EventType.KeyDown)
        {
            
            if (e.keyCode == KeyCode.Keypad4)
            {
                ExportDir = 4;
                mid1Cor = Color.red;
                mid2Cor = Color.green;
                mid3Cor = Color.green;
                mid4Cor = Color.green;
            }
            if (e.keyCode == KeyCode.Keypad6)
            {
                ExportDir = 6;
                mid1Cor = Color.green;
                mid2Cor = Color.green;
                mid3Cor = Color.red;
                mid4Cor = Color.green;
            }
            if (e.keyCode == KeyCode.Keypad2)
            {
                ExportDir = 2;
                mid1Cor = Color.green;
                mid2Cor = Color.green;
                mid3Cor = Color.green;
                mid4Cor = Color.red;
            }
            if (e.keyCode == KeyCode.Keypad8)
            {
                ExportDir = 8;
                mid1Cor = Color.green;
                mid2Cor = Color.red;
                mid3Cor = Color.green;
                mid4Cor = Color.green;
            }
            if (e.keyCode == KeyCode.KeypadPlus)
            {
                //ExportDir = 4;
                Plus(ExportDir);
            }
            if (e.keyCode == KeyCode.KeypadMinus)
            {
                //ExportDir = 4;
                Minus(ExportDir);
            }
        }
       
    }
    void Plus(int dir)
    {

        if (dir == 4)
        {
            dot1.x -= EditorSpeed;
            dot2.x -= EditorSpeed;
        }
        else if (dir == 6)
        {
            dot3.x += EditorSpeed;
            dot4.x += EditorSpeed;
        }
        else if (dir == 2)
        {
            dot1.z -= EditorSpeed;
            dot4.z -= EditorSpeed;
        }
        else if (dir == 8)
        {
            dot2.z += EditorSpeed;
            dot3.z += EditorSpeed;
        }
        else
        {
            return;
        }
    }
    void Minus(int dir)
    {

        if (dir == 4)
        {
            dot1.x += EditorSpeed;
            dot2.x += EditorSpeed;
        }
        else if (dir == 6)
        {
            dot3.x -= EditorSpeed;
            dot4.x -= EditorSpeed;
        }
        else if (dir == 2)
        {
            dot1.z += EditorSpeed;
            dot4.z += EditorSpeed;
        }
        else if (dir == 8)
        {
            dot2.z -= EditorSpeed;
            dot3.z -= EditorSpeed;
        }
        else
        {
            return;
        }
    }
    private void OnGUI()
    {
        GUILayout.BeginVertical();
        //標籤
        GUILayout.BeginHorizontal();
        GUILayout.Box("輸入相應的引數", TitleBoxStyle(), GUILayout.Height(60),GUILayout.ExpandWidth(true));
        GUILayout.EndHorizontal();
        GUILayout.Space(10);
        
        GUILayout.BeginHorizontal();
        GUIStyle boxStyle = new GUIStyle();
        boxStyle.alignment = TextAnchor.MiddleCenter;
        GUILayout.Box("當前移動速度"+ EditorSpeed, boxStyle, GUILayout.Height(30), GUILayout.Width(80));
        GUILayout.Space(10);
        EditorSpeed = GUILayout.HorizontalSlider(EditorSpeed, 0.01f, 1);
        GUILayout.EndHorizontal();
       
        GUILayout.EndVertical();
    }
   
  
}

  希望這次的分享對大家有點收穫,不好的地方希望大家能幫我指