zoukankan      html  css  js  c++  java
  • Unity 编辑器扩展 场景视图内控制对象

    http://blog.csdn.net/akof1314/article/details/38129031

    假设有一个敌人生成器类,其中有个属性range用来表示敌人生成的范围区域大小,那么可以用OnDrawGizmos函数来绘制它在场景视图所代表的区域大小,便于开发调试。这个敌人生成器类,类似如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    using UnityEngine;
    using System.Collections;

    public class EnemySpawn : MonoBehaviour 
    {
        public float range;

        void OnDrawGizmos()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireCube(transform.position, new Vector3(range, 0, range));
        }

        void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.yellow;
            Gizmos.DrawWireCube(transform.position, new Vector3(range, 0, range));
        }
    }
    可以在场景视图看到,当未选中改对象时,为绿色边框表示区域大小,当选中时,则为黄色。如下图所示:
    未选中:

    选中:
     
    如何直接在场景视图进行调整区域的大小呢,即直接调整range值,而不用在检视器里进行设置。这可以用控制柄来达到,即Handles类。创建一个编辑器扩展类,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    using UnityEngine;
    using UnityEditor;

    [CustomEditor(typeof(EnemySpawn))]
    public class EnemySpawnEditor : Editor 
    {
        void OnSceneGUI()
        {
            EnemySpawn enemySpawn = target as EnemySpawn;
            Vector3 pos = enemySpawn.transform.position;

            // 计算4个角落
            Vector3 v0 = new Vector3(pos.x - enemySpawn.range / 2, pos.y, pos.z - enemySpawn.range / 2);
            Vector3 v1 = new Vector3(pos.x + enemySpawn.range / 2, pos.y, pos.z + enemySpawn.range / 2);

            float y = v0.y;
            Vector3[] corners = new Vector3[4];
            corners[0] = new Vector3(v0.x, y, v0.z);
            corners[1] = new Vector3(v0.x, y, v1.z);
            corners[2] = new Vector3(v1.x, y, v1.z);
            corners[3] = new Vector3(v1.x, y, v0.z);

            // 4个缩放值控制柄
            for (int i = 0; i < 4; ++i)
            {
                enemySpawn.range = Handles.ScaleValueHandle(enemySpawn.range,
                            corners[i],
                            Quaternion.identity,
                            1,
                            Handles.SphereCap,
                            1);

                Handles.Label(corners[i], i.ToString());
            }

            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
            }
        }
    }
    现在可以在场景视图里看到这个对象边框各有一个球体,进行拉动球体,可以看到区域大小值range进行变化了,如下图所示:
     
    现在用控制柄改变的range值,无法进行撤销,这样就无法进行回滚操作,为其添加撤销功能,代码更改为如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    using UnityEngine;
    using UnityEditor;

    [CustomEditor(typeof(EnemySpawn))]
    public class EnemySpawnEditor : Editor 
    {
        void OnSceneGUI()
        {
            EnemySpawn enemySpawn = target as EnemySpawn;
            Vector3 pos = enemySpawn.transform.position;

            // 计算4个角落
            Vector3 v0 = new Vector3(pos.x - enemySpawn.range / 2, pos.y, pos.z - enemySpawn.range / 2);
            Vector3 v1 = new Vector3(pos.x + enemySpawn.range / 2, pos.y, pos.z + enemySpawn.range / 2);

            float y = v0.y;
            Vector3[] corners = new Vector3[4];
            corners[0] = new Vector3(v0.x, y, v0.z);
            corners[1] = new Vector3(v0.x, y, v1.z);
            corners[2] = new Vector3(v1.x, y, v1.z);
            corners[3] = new Vector3(v1.x, y, v0.z);
            
            EditorGUI.BeginChangeCheck();
            float scaleValue = enemySpawn.range;
            float newRange = scaleValue;

            // 4个缩放值控制柄
            for (int i = 0; i < 4; ++i)
            {
                scaleValue = Handles.ScaleValueHandle(enemySpawn.range,
                            corners[i],
                            Quaternion.identity,
                            1,
                            Handles.SphereCap,
                            1);
                newRange = scaleValue == enemySpawn.range ? newRange : scaleValue;

                Handles.Label(corners[i], i.ToString());
            }

            if (EditorGUI.EndChangeCheck())
            {
                // 记录对象以便进行撤销
                Undo.RecordObject(enemySpawn, "Change Range");
                enemySpawn.range = newRange;

                EditorUtility.SetDirty(target);
            }
        }
    }
    现在再次进行拉动,即可在Edit→Undo下看到撤销信息了,如下图所示:
     
    对其他人来讲,可能看到这些球体,不知道是可以拖动的,也不明白拖动它之后会产生什么样的效果,那么,如果能够在鼠标移动到球体上面的时候,能够提示出这些信息就好了。这里,增加下鼠标在球体上时,鼠标箭头会变化成带缩放提示的图标,代码更改为如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
    using UnityEngine;
    using UnityEditor;

    [CustomEditor(typeof(EnemySpawn))]
    public class EnemySpawnEditor : Editor
    {
        void OnSceneGUI()
        {
            EnemySpawn enemySpawn = target as EnemySpawn;
            Vector3 pos = enemySpawn.transform.position;

            // 计算4个角落
            Vector3 v0 = new Vector3(pos.x - enemySpawn.range / 2, pos.y, pos.z - enemySpawn.range / 2);
            Vector3 v1 = new Vector3(pos.x + enemySpawn.range / 2, pos.y, pos.z + enemySpawn.range / 2);

            float y = v0.y;
            Vector3[] corners = new Vector3[4];
            corners[0] = new Vector3(v0.x, y, v0.z);
            corners[1] = new Vector3(v0.x, y, v1.z);
            corners[2] = new Vector3(v1.x, y, v1.z);
            corners[3] = new Vector3(v1.x, y, v0.z);

            EditorGUI.BeginChangeCheck();
            float scaleValue = enemySpawn.range;
            float newRange = scaleValue;
            float sizeHandle = 1.0f;
            float realSize = sizeHandle * 0.1f; // 实际为0.15f,比它小才能更精确显示鼠标

            // 4个缩放值控制柄
            for (int i = 0; i < 4; ++i)
            {
                v0 = new Vector3(corners[i].x - realSize, y, corners[i].z - realSize);
                v1 = new Vector3(corners[i].x + realSize, y, corners[i].z + realSize);

                // 换算成GUI坐标
                Vector2[] handles = new Vector2[4];
                handles[0] = HandleUtility.WorldToGUIPoint(new Vector3(v0.x, y, v0.z));
                handles[1] = HandleUtility.WorldToGUIPoint(new Vector3(v0.x, y, v1.z));
                handles[2] = HandleUtility.WorldToGUIPoint(new Vector3(v1.x, y, v1.z));
                handles[3] = HandleUtility.WorldToGUIPoint(new Vector3(v1.x, y, v0.z));

                Bounds b = new Bounds(handles[0], Vector3.zero);
                for (int j = 1; j < 4; ++j)
                {
                    b.Encapsulate(handles[j]);
                }

                Vector2 min = b.min;
                Vector2 max = b.max;
                Rect rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y);

                // 调试绘制是否计算正确
                Handles.BeginGUI();
                GUI.Box(rect, rect.ToString());
                Handles.EndGUI();

                // 是否鼠标在控制柄上
                if (rect.Contains(Event.current.mousePosition))
                {
                    // 显示缩放图标的箭头
                    EditorGUIUtility.AddCursorRect(rect, MouseCursor.ScaleArrow);
                }

                scaleValue = Handles.ScaleValueHandle(enemySpawn.range,
                            corners[i],
                            Quaternion.identity,
                            sizeHandle,
                            Handles.SphereCap,
                            1);
                newRange = scaleValue == enemySpawn.range ? newRange : scaleValue;

                Handles.Label(corners[i], i.ToString());
            }

            if (EditorGUI.EndChangeCheck())
            {
                // 记录对象以便进行撤销
                Undo.RecordObject(enemySpawn, "Change Range");
                enemySpawn.range = newRange;

                EditorUtility.SetDirty(target);
            }
        }
    }
    这里只是模糊地计算了下球体控制柄的响应范围。现在可以在场景视图看到每个球体都有一个矩形包围着,当鼠标进入到这个矩形里面,就会改变鼠标图形,如下图所示:
    现在可以把调试绘制矩形框的给删除掉了,即删除以下代码:
    1
    2
    3
    4
     
    // 调试绘制是否计算正确
    Handles.BeginGUI();
    GUI.Box(rect, rect.ToString());
    Handles.EndGUI();
     
    参考资料:
    1.Unity3D研究院之拓展Scene视图(三) http://www.xuanyusong.com/archives/2303
    2.Unity3D 场景编辑器扩展学习笔记-Handles&Event http://blog.csdn.net/kun1234567/article/details/19477787
  • 相关阅读:
    linux c编程:Posix消息队列
    go语言之接口二
    linux c编程:FIFO
    python cookbook第三版学习笔记十九:未包装的函数添加参数
    linux c编程:popen
    linux c编程:管道
    Linux c编程:I/O多路复用之epoll
    Linux c编程:I/O多路复用之select
    inux c编程:记录锁
    python cookbook第三版学习笔记十八:可由用户修改的装饰器
  • 原文地址:https://www.cnblogs.com/123ing/p/3964033.html
Copyright © 2011-2022 走看看