描述在我们开发项目的时候,可能会遇到一些特殊的情况,比如场景里面有几个十几个甚至几十个看起来相同的物体,但是其实有几个物体可能在部分组件数值是特殊的,需要经常修改测试,想直观的在Scene标识这个特殊物体。又或者一个正方体(不管如何旋转90度,scene视图看起来都一样),我们想直观的在Scene视图了解这个正方体的朝向,等等。这些需求我们都可以通过自定义Scene视图来实现(其实是实现MonoBehaviour下OnDrawGizmos或OnDrawGizmosSelected方法,实现自定义绘制,并只能在Scene视图下查看) 
再比如,我们做一个类似《我的世界》这样的游戏,所有物体的大小位置都是按一个定好的基数。比如定好所有的物体都是1*1*1的,那么他们移动的时候也需要1单位1单位的移动,如图拼积木一般。加入我们有十个这样的物体需要把它拼成一个门的形状,那么一种方法自然是一个个物体去修改他的Inspector下的坐标。这样我们不仅要计算每个点的坐标,还要一个个修改,要是物体更多场景更大就很麻烦。当然我们也可以在Scene视图下拖动物体,但是我们很难精确到每次拖动都是1单位。这时候,我们就可以自定义Scene视图来处理。(实现Editor下的OnSceneGUI方法) 
实现过程首先,我们讲一讲MonoBehaviour下OnDrawGizmos或OnDrawGizmosSelected方法。既然是MonoBehaviour类,我们就需要创建一个脚本,继承于MonoBehaviour,然后实现这个两个方法,最后将脚本挂在我们需要的物体上即可。 OnDrawGizmos:每帧调用,里面实现的绘制在Scene视图可见
OnDrawGizmosSelected:物体被选中的时候每帧调用
public class CustomCube : MonoBehaviour { Gizmos.color = Color.black; Gizmos.DrawWireCube(GetComponent<Renderer>().bounds.center, GetComponent<Renderer>().bounds.size); Gizmos.color = Color.yellow; Gizmos.DrawLine(transform.position, transform.position + transform.up * 2); void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireCube(GetComponent<Renderer>().bounds.center, GetComponent<Renderer>().bounds.size);
如果我们想要在Scene视图上显示一些GUI控件,即上述例子的第二种情况,我们就需要用到OnSceneGUI方法。需要注意的是这个方法是在Editor基类下的,所以我们生成的脚本要继承Editor并放在Editor目录下。 OnSceneGUI:只有当物体选中的时候每帧会调用。
下面这个方法实现的是,带有CustomCube组件的物体,被选中的时候,Scene场景下会显示该物体的名称和坐标,同时会显示四个按钮提供按单位长度位移。并且当你在Scene视图使用箭头拖动该物体时,也是按单位长度位移。 [CustomEditor(typeof(CustomCube))] public class CustomCubeEditor : Editor { m_cube = (CustomCube)target; m_trans = m_cube.transform; Vector3 posTemp = m_trans.localPosition; float x = Mathf.RoundToInt(posTemp.x); float y = Mathf.RoundToInt(posTemp.y); float z = Mathf.RoundToInt(posTemp.z); m_trans.localPosition = new Vector3(x, y, z); Handles.Label(m_trans.position + Vector3.up * 3, m_cube.name + " : " + m_trans.position.ToString()); GUILayout.BeginArea(new Rect(100, 100, 100, 100)); if(GUILayout.Button("上移")) { m_trans.position += Vector3.up; if(GUILayout.Button("下移")) { m_trans.position += Vector3.down; if(GUILayout.Button("左移")) { m_trans.position += Vector3.left; if(GUILayout.Button("右移")) { m_trans.position += Vector3.right;
上述的方法需要在物品选中的情况下,如果我们要处理未选中物品,在Scene视图额外显示一些属性的话(比如显示物品名称)。可以使用DrawGizmo标签来实现,如下,脚本要放在Editor文件夹下。 public class SceneEditor : MonoBehaviour { [DrawGizmo(GizmoType.NonSelected)] static void DrawGameObjectName(Transform transform, GizmoType gizmoType) { Handles.Label(transform.position, transform.gameObject.name);
[DrawGizmo(GizmoType.NonSelected)],即没有选中物体的时候会调用下面的方法。方法名可以自定义,第一个参数可以是自定义的一个class(Transform,GameObject或者你自己写的组件,如果物品不包含该类型,则不会调用该方法),第二个参数必须为GizmoType。 效果如下: 
GizmoType支持的类型如下:(NotSelected 和 SelectedOrChild已弃用)
Pickable | gizmo在编辑器中可被选中 | NotInSelectionHierarchy | 物品没有被选中并且其父节点也没被选中 | Selected | 物体选中的时候 | Active | 物体可见的时候 | InSelectionHierarchy | 物品被选中或选中其中一个子物体 | NonSelected | 物体没有被选中的时候 |
备注:上述三种方法都可以在Scene视图上做一些扩展,其实很多情况也是互通的,比如你可以在OnDrawGizmos方法去添加Handles.Label显示物体名称,或者做拖动的单位长度限制等等。
|