孙广东 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 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));
}
}
}
3、Layingthe groundwork for our handles为我们处理奠定基础
4、Creatinga handle
5、Drawinglines in the scene view
6、Coloringhandles
7、Dynamicallysizing 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();
}
}
8、Previewingthe status bar
9、Sizinga status bar with handles
10、Snappinghandles
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;
}
}
运行效果:
11、Executingscripts 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
………………………………………………..
}
12、Drawinga 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的
13、Visualizingour 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();
}
}
看看效果:
通过拖动四个中的任何一个绿色的小圆,就可以改变范围了。
14、Drawingthe 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();
}
}
通过拖动两个红色的小圆圈,就确定了,炮筒的攻击视野了。
15、Visualizingthe 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();
看看效果呢?
16、IntroducingGizmos
来到 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);
}
17、DrawingGizmos 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);
}
}