• Unity 编辑器扩展 场景视图内控制对象


    如果有一个敌人生成器类。当中有个属性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

  • 相关阅读:
    java多线程(八)-死锁问题和java多线程总结
    java多线程(七)-线程之间的 协作
    java多线程(六)-线程的状态和常用的方法
    在SOUI中使用网格布局
    SOUI视频教程
    在SOUI中使用动态多语言切换
    在SOUI中使用窗口自適應大小
    在SOUI中使用线性布局
    搜索引擎广告过滤Chrome插件
    第三十四篇:在SOUI中使用异步通知
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6928926.html
Copyright © 2020-2023  润新知