Unity Editor Extensions – Handle 和Gizmos私人定制

孙广东  2015.6.20

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

                }

}

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

                }

}

??

时间: 2024-10-27 05:55:46

Unity Editor Extensions – Handle 和Gizmos私人定制的相关文章

Unity Editor Extensions – Custom Inspectors

?? 转载请注明出处:http://blog.csdn.net/u010019717 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/space-uid-18602.html 这是在"Unity Editor Extension"系列的第 2 次帖子. post描述了为创建自定义inspectors面板在 Unity 编辑器的基本步骤.在该系列的下一个posts,我将深入探讨更高级的主题,例如inspectors及Unity's serializa

Unity Editor Extensions – Menu Items

转载请注明出处:http://blog.csdn.net/u010019717 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/space-uid-18602.html Unity 编辑器允许添加自定义菜单的外观和行为类似内置菜单.这可以用于添加经常常用的功能,可直接从编辑器UI操作. 在这篇文章中,我将展示如何利用新的菜单menu items,Unity 编辑器中创建并尝试提供真实世界的例子用法,对于每个描述的topic. 添加菜单项 为了向top-lev

Unity Editor 执行时机的问题

在上上篇博文,我提到了Unity编辑器. 即引用 Unity Editor命名空间,且添加[CustomEditor(typeof(Class))] 就可以定制对应Class的Inspector面板. 但这个类本身,也就是ClassEditor的执行事实上并不需要启动Unity项目 这个并不是什么很难发现的事情,因为编写Editor的过程中,对应类的Inspector面板就会变化 只不过如果这个Editor类存在编译错误的话,就会直接报错,从而项目无法启动 原文地址:https://www.cn

“私人定制”——开启定制家具2.0时代

说起定制,最早还属于高级服装和珠宝奢侈品这类范畴,近几年已在家居行业悄然兴起,衣柜.橱柜成为了人们最青睐定制的家具.就在人们还在谈论着家具定制的新鲜感和优越感时,一场更大的定制革命今天已经来临,家具定制的2.0版"全屋定制".   62.9%的消费者倾向于全屋定制 随着80后逐渐成为家居市场消费的主力军,消费习惯和理念和其父辈完全不一样,传统家居模式很难满足他们的个性化需求,而"私人定制"就此悄然走红.与传统家居相比,定制家具可根据消费者自己的喜好.占用空间的大小以

私人定制推送铃声

最好的用户体验就是私人定制,今天说下推送铃声的私人定制. 分为3个步骤: 1.制作推送提醒铃声 一般的iphone手机铃声都能够,限时30s之内. 2.倒入项目 将制作好的铃声加入到xcode的project项目中 3.改动推送json(改动后台) $body['aps'] = array( 'alert' => $message, //'sound' => 'default',//这个是默认的 'sound' =>'sub.m4r', //sub.m4r为你加入到项目中的声音文件名 '

自定义 Android Preference——SpinnerPreference的私人定制

因客户需求SpinnerPreference,网上各种搜索不到,无奈只能重写组件,现将过程分享大家. 自定义SpinnerPreference 一:首先从扩展preference开始:类文件必须继承自Preference并实现构造函数,如下 public MySpinnerPreference(Context context) { super(context); } public MySpinnerPreference(Context context, AttributeSet attrs) {

圆满结束【一对一私人定制,我和马哥有个约会】

[一对一私人定制,我和马哥有个约会]活动圆满结束 7.28日马哥一对一沟通交流会圆满结束了,几位幸运的马哥铁粉纷纷反馈收获满满. 他们不仅零距离和马哥一对一进行了沟通,更收获了满满干货,在运维道路上开阔了视野,还认识了志同道合的朋友. 马哥在线上跟同学交流,答疑解惑 学员反馈及群里沟通,直接跟马哥沟通,说服力和指导力都会比较信服 这次马哥也拿出了价值1200元的内部技术资料分享给报名的120个用户,很多学员要求尽快举办第二期活动,后续51CTO学院还会举办更多精彩的活动回馈广大用户盆友的,敬请期

私人定制javascript中数组小知识点(Only For Me)

先上笑话,1.刚看到一个游泳的,想起公司组织去三亚旅游,老板跳海里,各种挣扎,捞上来老板第一句话:我记得我会游泳的啊. 2.媳妇说:老公对不起,我把你新买的自行车撞散架了! 老公:没事宝贝,你若安好,便是晴天! 媳妇说:老公你太有诗意了. 老公:滚犊子,安不好我整死你! 数组的概念 javascript数组是值得有序集合,不过它实属一个javascript对象的特殊形式,这是一个很重点的定性. 创建数组 1.var a=new Array();//等同于[] 2.var a=new Array(

私人定制-代码生成器2

大家好最近一直比较忙没有及时更新软件,首先说声抱歉.这次为大家带来的是v2.3.0版本,这次主要更新有如下几点: 一.V2.3.0新增功能:1.支持生成数据库常用脚本 Update.InsertAndUpdate . 2.支持NHibernate映射文件Hbm文件生成 .3.支持Mssql2000数据库 .4.新增了字段类型与目标类型映射 .5.优化了进度条显示,主要是程序执行和界面显示不同步问题 .6.对代码进行了适当的重构,减少了冗余代码.提高了代码复用率.代码每页不超过100行.7.优化软