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

时间: 2024-11-07 03:28:05

Unity 编辑器扩展 场景视图内控制对象的相关文章

Unity编辑器扩展chapter1

Unity编辑器扩展chapter1 unity通过提供EditorScript API 的方式为我们提供了方便强大的编辑器扩展途径.学好这一部分可以使我们学会编写一些工具来提高效率,甚至可以自制一些小的插件应用的项目工程中去,达到复用的目的.今天首先创建一个新场景生成的菜单项,生成的场景已经绑定好需要的游戏对象及脚本. Tips:1.官方API 2.编辑器扩展脚本都需放在Editor文件夹下,Editor的层级和数目没有要求 EditorUtil.cs :编辑器扩展类,向外部提供编辑器扩展方法

Unity编辑器扩展Texture显示选择框

学习NGUI插件的时候,突然间有一个问题为什么它这些属性可以通过弹出窗口来选中呢? 而我自己写的组件只能使用手动拖放的方式=.=. Unity开发了组件Inspector视图扩展API,如果我们要写插件方便别人来使用,使用编辑器扩展API让我们的组件显示的更华丽,使用方便 Texture弹出选择框选中图片赋值: 1个组件对应1个Edit扩展器,继承Editor必须让入Editor文件夹下 MyComponent: using UnityEngine; using System.Collectio

Unity编辑器扩展相关知识

1.一些类 1.1.GUI 界面 1.2.GUILayout 界面布局 1.3.GUIStyle 界面样式 1.4.GUIContent 界面内容 1.5.Editor 编辑器 1.6.EditorUtility 编辑器工具 1.7.EditorWindow 编辑器窗口 1.8.EditorGUI 编辑器界面 1.9.EditorGUILayout 编辑器界面布局 1.10.EditorGUIUtility 编辑器界面工具 1.11.Handles 控制柄 1.12.HandleUtility

unity编辑器扩展一批量生成图片预制

觉得自己正在慢慢退化,所以以后坚持写博客记录一下成长. 今天分享一个以前用到的一个功能,unity编辑器的一个扩张工具--批量生成图片,有兴趣的朋友可以进行扩展 闲话少说直接上代码: namespace Game.Utility{    public class BatchCreatePrefab : EditorWindow    {        [MenuItem("Tools/生成预制")]        private static void PrefabWrapTool()

Unity 编辑器扩展自定义窗体

这次看见Unity还可以自定义弹出窗体,让我很好奇.于是就去网上找文章看了看. 如果想自定义窗体需要把类放入Editor文件夹下面. 代码如下: using UnityEngine; using UnityEditor; public class MyEditor : EditorWindow { [MenuItem("GameObject/window")] static void AddWindow() { Rect wr = new Rect(0, 0, 500, 500); M

Unity编辑器扩展 – Menu Items

参考:https://unity3d.com/cn/learn/tutorials/topics/interface-essentials/unity-editor-extensions-menu-items 通过Unity MenuItem属性类可以扩展主菜单.属性栏内容菜单.层级栏菜单及资源栏菜单. MenuItem可以将任意静态函数转换为菜单命令,只有静态函数能使用MenuItem属性. 添加菜单选项 添加一个简单的主菜单按钮 using UnityEditor; using UnityE

Unity编辑器扩展-Custom List, displaying data your way

本文转自http://catlikecoding.com/unity/tutorials/editor/custom-list/ Custom List, displaying data your way In this Unity C# tutorial you will create a custom visualization for arrays and lists in the editor. You will learn to create a custom editor use S

Unity编辑器扩展

代码放在Assets/Editor中: using UnityEngine; using UnityEditor; public class MyWindow : EditorWindow { const string MenuName = "Atwal Code Snippet"; enum Code_Type { input_code, rigidbody_force_code, camera_follow } static Code_Type type = 0; static s

Unity 编辑器下控制播放粒子

在Unity编辑器的Scene视图进行控制播放粒子ParticleSystem,可以借助方法Simulate,具体可以参照以下例子: 创建一个空对象ParticleAll,在这个对象下添加一个粒子(要添加多个粒子的话,添加到这个粒子之下),此时选中粒子,可以看到Scene视图预览播放粒子效果.附上新脚本EditParticleSystem,此为空脚本,如下: C# Code 1 2 3 4 5 6 using UnityEngine; public class EditParticleSyste