Unity Editor Extensions – Handle 和Gizmos私人定制

孙广东  2015.6.20  

先贴一个 Grid网格吧。  可以标记一个对象的正方形范围等

Unity Editor Extensions – Handle 和Gizmos私人定制_第1张图片

拖拽到指定的对象就OK了。

using UnityEngine;
using System.Collections;
 
// DrawGizmoGrid.cs
// draws a useful reference grid in the editor in Unity. 
// 09/01/15 - Hayden Scott-Baron
// twitter.com/docky 
// no attribution needed, but please tell me if you like it ^_^
 
public class DrawGizmoGrid : MonoBehaviour
{
	// universal grid scale
	public float gridScale = 1f; 
 
	// extents of the grid
	public int minX = -15; 
	public int minY = -15; 
	public int maxX = 15; 
	public int maxY = 15; 
 
	// nudges the whole grid rel
	public Vector3 gridOffset = Vector3.zero; 
 
	// is this an XY or an XZ grid?
	public bool topDownGrid = true; 
 
	// choose a colour for the gizmos
	public int gizmoMajorLines = 5; 
	public Color gizmoLineColor = new Color (0.4f, 0.4f, 0.3f, 1f);  
 
	// rename + centre the gameobject upon first time dragging the script into the editor. 
	void Reset ()
	{
		if (name == "GameObject")
			name = "~~ GIZMO GRID ~~"; 
 
		transform.position = Vector3.zero; 
	}
 
	// draw the grid :) 
	void OnDrawGizmos ()
	{
		// orient to the gameobject, so you can rotate the grid independently if desired
		Gizmos.matrix = transform.localToWorldMatrix;
 
		// set colours
		Color dimColor = new Color(gizmoLineColor.r, gizmoLineColor.g, gizmoLineColor.b, 0.25f* gizmoLineColor.a); 
		Color brightColor = Color.Lerp (Color.white, gizmoLineColor, 0.75f); 
 
		// draw the horizontal lines
		for (int x = minX; x < maxX+1; x++)
		{
			// find major lines
			Gizmos.color = (x % gizmoMajorLines == 0 ? gizmoLineColor : dimColor); 
			if (x == 0)
				Gizmos.color = brightColor;
 
			Vector3 pos1 = new Vector3(x, minY, 0) * gridScale;  
			Vector3 pos2 = new Vector3(x, maxY, 0) * gridScale;  
 
			// convert to topdown/overhead units if necessary
			if (topDownGrid)
			{
				pos1 = new Vector3(pos1.x, 0, pos1.y); 
				pos2 = new Vector3(pos2.x, 0, pos2.y); 
			}
 
			Gizmos.DrawLine ((gridOffset + pos1), (gridOffset + pos2)); 
		}
 
		// draw the vertical lines
		for (int y = minY; y < maxY+1; y++)
		{
			// find major lines
			Gizmos.color = (y % gizmoMajorLines == 0 ? gizmoLineColor : dimColor); 
			if (y == 0)
				Gizmos.color = brightColor;
 
			Vector3 pos1 = new Vector3(minX, y, 0) * gridScale;  
			Vector3 pos2 = new Vector3(maxX, y, 0) * gridScale;  
 
			// convert to topdown/overhead units if necessary
			if (topDownGrid)
			{
				pos1 = new Vector3(pos1.x, 0, pos1.y); 
				pos2 = new Vector3(pos2.x, 0, pos2.y); 
			}
 
			Gizmos.DrawLine ((gridOffset + pos1), (gridOffset + pos2)); 
		}
	}
}


3Layingthe groundwork for our handles为我们处理奠定基础

4Creatinga handle

5Drawinglines in the scene view

6Coloringhandles

7Dynamicallysizing handles

 

public class TerrainPiece : MonoBehaviour 
{

                public SpriteRenderer spriteRenderer;
                public Vector3 mountPoint;
                void Awake () 
                {
                                if (spriteRenderer == null)

                                                spriteRenderer = GetComponentInChildren();
                }
}

 

下面就来定制这个类:

[CustomEditor(typeof(TerrainPiece))]

public class TerrainPieceEditor : Editor

{

                SerializedProperty mountPointProp;              // TerrainPiece. mountPoint

                TerrainPiece terrainPiece;                                                                                               // TerrainPiece

   

                void OnEnable()

                {

                                terrainPiece = (TerrainPiece) target;

                                mountPointProp = serializedObject.FindProperty("mountPoint");

                }
 
                void OnSceneGUI()

                {

                                serializedObject.Update();

 

                                Vector3 worldMountPt = terrainPiece.transform.TransformPoint(mountPointProp.vector3Value);     // 转成世界坐标系

 

                                float sizeFactor = HandleUtility.GetHandleSize(worldMountPt) * 0.25f;            // 这样就不会随着scene面板的远近而动态改变大小,一直不变。

 

                                Handles.color = Color.magenta;                                     // 设置颜色

                                worldMountPt = Handles.FreeMoveHandle(worldMountPt, Quaternion.identity, sizeFactor * 0.2f, Vector3.zero, Handles.RectangleCap);     // 拖动handle来改变值

 

                                Handles.DrawLine(worldMountPt - Vector3.up * sizeFactor, worldMountPt + Vector3.up * sizeFactor);

                                Handles.DrawLine(worldMountPt - Vector3.right * sizeFactor, worldMountPt + Vector3.right * sizeFactor);

 

                                Vector3 mountPointLocal = terrainPiece.transform.InverseTransformPoint(worldMountPt);     // 转成相对父级的本地坐标

                                mountPointLocal.z = 0;

                                mountPointProp.vector3Value = mountPointLocal;

                                 

                                serializedObject.ApplyModifiedProperties();     

                }

}


 

 

8Previewingthe status bar

9Sizinga status bar with handles

10Snappinghandles

 

public class Statusbar : MonoBehaviour 

{

                publicstring barTextureName = "statusbar";             //The name of our bar texture (must be located in Resources folder)

                publicGradient colorGrad;

                publicVector2 offset;

                publicVector2 drawSize = new Vector2(5f, 1f);

 

                protectedTexture2D barTexture;

                protectedfloat targetPercent = 1f;                                //The normalized percentage the bar is to represent

                protectedfloat displayPercent = 1f;              //The value actually used to render the bar, allows us to animate the bar towardthe targetPercent value

                protectedRect srcRect;                                                                    //The rect of the area to use from the source texture

                protectedRect scrExtents;                                                              //The rect that defines the screen area extents

 

                protectedVector2 size;

。。。。。。。。。。。。。。。。。。。。。。

}

---- Editor 的定制显示?:

 

[CustomEditor(typeof(Statusbar))]

public class StatusbarEditor : Editor 

{

                SerializedPropertyoffsetProp;

                SerializedPropertydrawSizeProp;

                Statusbarbar;                                                                                                     //要定制的类

                staticTexture2D barTexture;                                                           //用于显示加载的图片

 

                voidOnEnable()

                {

                                bar= (Statusbar) target;

 

                                offsetProp= serializedObject.FindProperty("offset");

                                drawSizeProp= serializedObject.FindProperty("drawSize");

 

                                barTexture= Resources.Load(bar.barTextureName, typeof(Texture2D)) as Texture2D;

                }

 

                voidOnSceneGUI()

                {

                                serializedObject.Update();

 

                                DrawBar();

                                DrawHandles();

 

                                serializedObject.ApplyModifiedProperties();

                }

 

                voidDrawBar()

                {

                                Vector2pos = HandleUtility.WorldToGUIPoint(bar.transform.position +(Vector3)bar.offset);                                     // 坐标转换

 

                                Vector2size = bar.drawSize / bar.GetWorldUnitsPerPixel(Camera.current);                      //大小

 

                                RectscreenRect = new Rect(pos.x - size.x * 0.5f, pos.y - size.y * 0.5f,

                                                           size.x, size.y);                                           // 显示位置

 

                                Handles.BeginGUI();

                                GUI.DrawTexture(screenRect,barTexture);                                                                //显示图片

                                Handles.EndGUI();

                }

 

                voidDrawHandles()

                {

                                Handles.matrix= bar.transform.localToWorldMatrix;      // 矩阵变换初值

 

                                Vector3barPos = offsetProp.vector2Value;                                                 //位置初值

                                floathandleSize = HandleUtility.GetHandleSize(barPos) * 0.1f;                            // 大小初值

 

                                Handles.color= Color.green;                                                                           //设置颜色

 

                                //Bar position/offset:                                                                                        //计算位置,这是中间的圆handle

                                barPos= Handles.FreeMoveHandle(barPos, Quaternion.identity, handleSize, Vector3.zero,Handles.CircleCap);

 

                                //Save new offset:

                                offsetProp.vector2Value= barPos;

 

                                // 通过拖拽改变大小

 

                                //Top handle:

                                Vector3handlePt = barPos + Vector3.up * bar.drawSize.y * 0.5f;

                                Vector3newPos = Handles.FreeMoveHandle(handlePt, Quaternion.identity, handleSize,Vector3.zero, Handles.RectangleCap);

                                Vector2delta = new Vector2(0, newPos.y - handlePt.y);

                                drawSizeProp.vector2Value+= delta;

 

                                //Bottom handle:

                                handlePt= barPos + Vector3.down * bar.drawSize.y * 0.5f;

                                newPos= Handles.FreeMoveHandle(handlePt, Quaternion.identity, handleSize,Vector3.zero, Handles.RectangleCap);

                                delta= new Vector2(0, newPos.y - handlePt.y);

                                drawSizeProp.vector2Value-= delta;

 

                                //Left handle:

                                handlePt= barPos + Vector3.left * bar.drawSize.x * 0.5f;

                                newPos= Handles.FreeMoveHandle(handlePt, Quaternion.identity, handleSize, Vector3.zero,Handles.RectangleCap);

                                delta= new Vector2(newPos.x - handlePt.x, 0);

                                drawSizeProp.vector2Value-= delta;

 

                                //Right handle:

                                handlePt= barPos + Vector3.right * bar.drawSize.x * 0.5f;

                                newPos= Handles.FreeMoveHandle(handlePt, Quaternion.identity, handleSize,Vector3.zero, Handles.RectangleCap);

                                delta= new Vector2(newPos.x - handlePt.x, 0);

                                drawSizeProp.vector2Value+= delta;

                }

}

 

Unity Editor Extensions – Handle 和Gizmos私人定制_第2张图片

Unity Editor Extensions – Handle 和Gizmos私人定制_第3张图片

运行效果:

 

 

11Executingscripts in edit  mode

 

[ExecuteInEditMode]

public class Statusbar : MonoBehaviour 

{  }

这样Statusbar中的代码就会执行了,在Game面板中就可以看到ship的上方有两个血条。

如果我拖动Scene面板中的血条或者大小,下方就会跟着改变。

 

还想这样改变大小怎么办:

添加如下:

[ExecuteInEditMode]

public class Statusbar : MonoBehaviour 

{

                voidOnGUI()

                {

………………………………………………..

#if UNITY_EDITOR

                                if(!Application.isPlaying)

                                                size= drawSize / GetWorldUnitsPerPixel(Camera.main);

#endif

………………………………………………..

                }

 

 

12Drawinga detection range indicator

// 可以在Scene中动态改变坦克的攻击范围:

[CustomEditor(typeof(GroundTurretAI))]

public class GroundTurretAIEditor : Editor 

{

                GroundTurretAIai;

                SerializedPropertyrangeProp;

 

                voidOnEnable()

                {

                                ai= (GroundTurretAI) target;          // 要定制的脚本

                                rangeProp= serializedObject.FindProperty("detectionRange");      // 得到其中的范围属性

                }

 

                voidOnSceneGUI()

                {

                                serializedObject.Update();

 

                                Handles.color= Color.green;

 

// RadiusHandle来拖来改变值

                                rangeProp.floatValue= Handles.RadiusHandle(Quaternion.identity, ai.transform.position,rangeProp.floatValue);

 

                                serializedObject.ApplyModifiedProperties();

                }

}

不过通过 拖动scene的视图可以发现,这个东西是3D的球形。

13、中单独做一个2D

 

13Visualizingour range indicator for 2D games

 

[CustomEditor(typeof(GroundTurretAI))]

public class GroundTurretAIEditor : Editor 

{

                GroundTurretAIai;

                SerializedPropertyrangeProp;

 

                void OnEnable()

                {

                                ai= (GroundTurretAI) target;

                                rangeProp= serializedObject.FindProperty("detectionRange");

                }

 

                voidOnSceneGUI()

                {

                                serializedObject.Update();

 

                                Handles.color= Color.green;

 

                                Vector3aiPos = ai.transform.position;

                                floathandleSize = HandleUtility.GetHandleSize(aiPos) * 0.15f;

 

                                //Left handle:

                                Vector3handlePos = aiPos + Vector3.left * rangeProp.floatValue;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.SphereCap);

                                rangeProp.floatValue= Vector3.Distance(aiPos, handlePos);

 

                                //Right handle:

                                handlePos= aiPos + Vector3.right * rangeProp.floatValue;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.SphereCap);

                                rangeProp.floatValue= Vector3.Distance(aiPos, handlePos);

 

                                //Top handle:

                                handlePos= aiPos + Vector3.up * rangeProp.floatValue;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.SphereCap);

                                rangeProp.floatValue= Vector3.Distance(aiPos, handlePos);

 

                                //Bottom handle:

                                handlePos= aiPos + Vector3.down * rangeProp.floatValue;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.SphereCap);

                                rangeProp.floatValue= Vector3.Distance(aiPos, handlePos);

 

                                //Detection area:

                                Handles.color= new Color(0, 1f, 0, 0.15f);

                                Handles.DrawSolidDisc(aiPos,Vector3.back, rangeProp.floatValue);

 

                                serializedObject.ApplyModifiedProperties();

                }

}

 

看看效果:

通过拖动四个中的任何一个绿色的小圆,就可以改变范围了。

 

 

14Drawingthe turret field of fire handles

 

[CustomEditor(typeof(GroundTurret))]

public class GroundTurretEditor : Editor

{

                constfloat arcRadius = 12f;

                SerializedPropertyminAngleProp;

                SerializedPropertymaxAngleProp;

 

                GroundTurretturret;

 

                voidOnEnable()

                {

                                turret= (GroundTurret) target;   // 要定制的脚本

                                                                                                                                                //目标属性

                                minAngleProp= serializedObject.FindProperty("minAngle");

                                maxAngleProp= serializedObject.FindProperty("maxAngle");

                }

 

                voidOnSceneGUI()

                {

                                serializedObject.Update();

 

                                //Set the handle color:

                                Handles.color= Color.red;

 

                                //Draw handle controllings the minimum angle:

                                Vector3handlePos = turret.transform.position +turret.transform.TransformDirection(HandleHelper.GetVectorFromAngle(turret.minAngle))* arcRadius;

                                floathandleSize = HandleUtility.GetHandleSize(handlePos) * 0.1f;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.CircleCap);

 

                                //Calculate the angle from the new handle position:

                                minAngleProp.floatValue= HandleHelper.GetAngleFromHandlePos(handlePos, turret.transform);

 

 

                                //Draw handle controllings the maximum angle:

                                handlePos= turret.transform.position +turret.transform.TransformDirection(HandleHelper.GetVectorFromAngle(turret.maxAngle))* arcRadius;

                                handleSize= HandleUtility.GetHandleSize(handlePos) * 0.1f;

                                handlePos= Handles.FreeMoveHandle(handlePos, Quaternion.identity, handleSize,Vector3.zero, Handles.CircleCap);

                                

                                //Calculate the angle from the new handle position:

                                maxAngleProp.floatValue= HandleHelper.GetAngleFromHandlePos(handlePos, turret.transform);

 

                                serializedObject.ApplyModifiedProperties();

                }

}

Unity Editor Extensions – Handle 和Gizmos私人定制_第4张图片

通过拖动两个红色的小圆圈,就确定了,炮筒的攻击视野了。

 

 

15Visualizingthe turret field of fire

 

就在14、中的最后添加如下的内容:

                                //Calculate the angle from the new handle position:

                                maxAngleProp.floatValue= HandleHelper.GetAngleFromHandlePos(handlePos, turret.transform);

 

                                //Draw field-of-fire arc:

                                Handles.color= new Color(1f, 0, 0, 0.1f);

                                Vector3startVec = turret.transform.TransformDirection(HandleHelper.GetVectorFromAngle(minAngleProp.floatValue));

                                Handles.DrawSolidArc(turret.transform.position,Vector3.forward, startVec, maxAngleProp.floatValue - minAngleProp.floatValue,arcRadius);

 

                                serializedObject.ApplyModifiedProperties();

 

看看效果呢?

 

16IntroducingGizmos

来到 Gun.cs的脚本中添加如下的函数:

例如:

                voidOnDrawGizmos ()       // 函数会一直执行

                {

                                Gizmos.DrawSphere(transform.position, 3f);

}

 

                void OnDrawGizmosSelected()                      // 函数只有脚本所在对象被选择时执行

                {

                                Vector3shotVector = Vector3.zero;

                                Vector3arrowTip;

                                Vector3arrowLeft = Vector3.zero;

                                Vector3arrowRight = Vector3.zero;

                                floatarrowLength = 5f;

                                

                                switch(direction)

                                {

                                caseShotDirection.Up:

                                                shotVector= Vector3.up;

                                                arrowLeft= Vector3.left * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseShotDirection.Down:

                                                shotVector= Vector3.down;

                                                arrowLeft= Vector3.right * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseShotDirection.Left:

                                                shotVector= Vector3.left;

                                                arrowLeft= Vector3.down * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseShotDirection.Right:

                                                shotVector= Vector3.right;

                                                arrowLeft= Vector3.up * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                }

                                

                                arrowTip= shotVector * arrowLength;

                                arrowLeft+= shotVector * arrowLength * 0.7f;

                                arrowRight+= shotVector * arrowLength * 0.7f;

                                

                                Gizmos.color= Color.yellow;

                                Gizmos.matrix= transform.localToWorldMatrix;

                                

                                Gizmos.DrawLine(arrowTip,Vector3.zero);

                                Gizmos.DrawLine(arrowTip,arrowLeft);

                                Gizmos.DrawLine(arrowTip,arrowRight);

                }


Unity Editor Extensions – Handle 和Gizmos私人定制_第5张图片 

Unity Editor Extensions – Handle 和Gizmos私人定制_第6张图片

 

17DrawingGizmos in a custom editor to complete our course

16中,把相当于Editor的内容写在逻辑脚本中很不合适。

所以:

 

[CustomEditor(typeof(Gun))]

public class GunEditor : Editor 

{

                [DrawGizmo(GizmoType.SelectedOrChild)]

                staticvoid DrawDirection(Gun gun, GizmoType gizmoType)

                {

                                if(GizmoType.Selected == (gizmoType & GizmoType.Selected))   // 脚本所在对象被选择就不执行,父对象没有问题:

                                                return;

 

                                Vector3shotVector = Vector3.zero;

                                Vector3arrowTip;

                                Vector3arrowLeft = Vector3.zero;

                                Vector3arrowRight = Vector3.zero;

                                floatarrowLength = 5f;

                                

                                switch(gun.direction)

                                {

                                caseGun.ShotDirection.Up:

                                                shotVector= Vector3.up;

                                                arrowLeft= Vector3.left * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseGun.ShotDirection.Down:

                                                shotVector= Vector3.down;

                                                arrowLeft= Vector3.right * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseGun.ShotDirection.Left:

                                                shotVector= Vector3.left;

                                                arrowLeft= Vector3.down * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                caseGun.ShotDirection.Right:

                                                shotVector= Vector3.right;

                                                arrowLeft= Vector3.up * arrowLength * 0.2f;

                                                arrowRight= -arrowLeft;

                                                break;

                                }

                                

                                arrowTip= shotVector * arrowLength;

                                arrowLeft+= shotVector * arrowLength * 0.7f;

                                arrowRight+= shotVector * arrowLength * 0.7f;

                                

                                Gizmos.color= Color.yellow;

                                Gizmos.matrix= gun.transform.localToWorldMatrix;

                                

                                Gizmos.DrawLine(arrowTip,Vector3.zero);

                                Gizmos.DrawLine(arrowTip,arrowLeft);

                                Gizmos.DrawLine(arrowTip,arrowRight);

                }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 



你可能感兴趣的:(unity3d,Editor私人定制)