Unity Editor Extensions – Handle 和Gizmos私人定制

来源:互联网 发布:圣火明尊进阶数据 编辑:程序博客网 时间:2024/06/09 23:58

孙广东  2015.6.20  

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

拖拽到指定的对象就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 scalepublic float gridScale = 1f;  // extents of the gridpublic int minX = -15; public int minY = -15; public int maxX = 15; public int maxY = 15;  // nudges the whole grid relpublic Vector3 gridOffset = Vector3.zero;  // is this an XY or an XZ grid?public bool topDownGrid = true;  // choose a colour for the gizmospublic 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 desiredGizmos.matrix = transform.localToWorldMatrix; // set coloursColor 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 linesfor (int x = minX; x < maxX+1; x++){// find major linesGizmos.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 necessaryif (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 linesfor (int y = minY; y < maxY+1; y++){// find major linesGizmos.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 necessaryif (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<SpriteRenderer>();                }}

 

下面就来定制这个类:

[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;                }}

 

运行效果:

 

 

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();                }}

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

 

 

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);                }


 

 

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);                }}

 

 

 

 

 

 

 

 

 

 

 

 

 

 


1 1
原创粉丝点击