虽然mono是支持unicode的。可以在枚举里写中文,但是我还是觉得写英文好一些。可是在编辑器上策划是希望看到的是中文的,还有就是枚举的展示排序功能,策划在编辑的时候为了方便希望把常用的枚举排上前面。
把如下代码放到你的工程里就可以直接用了。
using UnityEngine;
using System;
#if UNITY_EDITOR
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#endif
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public class EnumLabelAttribute : PropertyAttribute
{
public string label;
public int[] order = new int[0] ;
public EnumLabelAttribute(string label)
{
this.label = label;
}
public EnumLabelAttribute(string label,params int[] order)
{
this.label = label;
this.order = order;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(EnumLabelAttribute))]
public class EnumLabelDrawer : PropertyDrawer
{
private Dictionary<string, string> customEnumNames = new Dictionary<string, string>();
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SetUpCustomEnumNames(property, property.enumNames);
if (property.propertyType == SerializedPropertyType.Enum)
{
EditorGUI.BeginChangeCheck();
string[] displayedOptions = property.enumNames
.Where(enumName => customEnumNames.ContainsKey(enumName))
.Select<string, string>(enumName => customEnumNames[enumName])
.ToArray();
int[] indexArray = GetIndexArray (enumLabelAttribute.order);
if(indexArray.Length != displayedOptions.Length)
{
indexArray = new int[displayedOptions.Length];
for(int i =0; i< indexArray.Length; i++){
indexArray[i] = i;
}
}
string[] items = new string[displayedOptions.Length];
items[0] = displayedOptions[0];
for (int i=0; i<displayedOptions.Length; i++) {
items[i] = displayedOptions[indexArray[i]];
}
int index = -1;
for (int i=0; i<indexArray.Length; i++) {
if (indexArray[i] == property.enumValueIndex) {
index = i;
break;
}
}
if ( (index == -1) && (property.enumValueIndex != -1) ) { SortingError (position,property,label); return; }
index = EditorGUI.Popup(position, enumLabelAttribute.label,index, items);
if (EditorGUI.EndChangeCheck())
{
if (index >= 0)
property.enumValueIndex = indexArray[index];
}
}
}
private EnumLabelAttribute enumLabelAttribute
{
get
{
return (EnumLabelAttribute)attribute;
}
}
public void SetUpCustomEnumNames(SerializedProperty property, string[] enumNames)
{
object[] customAttributes = fieldInfo.GetCustomAttributes(typeof(EnumLabelAttribute), false);
foreach (EnumLabelAttribute customAttribute in customAttributes)
{
Type enumType = fieldInfo.FieldType;
foreach (string enumName in enumNames)
{
FieldInfo field = enumType.GetField(enumName);
if (field == null) continue;
EnumLabelAttribute[] attrs = (EnumLabelAttribute[])field.GetCustomAttributes(customAttribute.GetType(), false);
if (!customEnumNames.ContainsKey(enumName))
{
foreach (EnumLabelAttribute labelAttribute in attrs)
{
customEnumNames.Add(enumName, labelAttribute.label);
}
}
}
}
}
int[] GetIndexArray (int[] order)
{
int[] indexArray = new int[order.Length];
for (int i = 0; i < order.Length; i++) {
int index = 0;
for (int j = 0; j < order.Length; j++) {
if (order[i] > order[j]) {
index++;
}
}
indexArray[i] = index;
}
return (indexArray);
}
void SortingError (Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, new GUIContent(label.text + " (sorting error)"));
EditorGUI.EndProperty();
}
}
public class EnumLabel
{
static public object GetEnum(Type type, SerializedObject serializedObject, string path)
{
SerializedProperty property = GetPropety(serializedObject,path);
return System.Enum.GetValues(type).GetValue(property.enumValueIndex);
}
static public object DrawEnum(Type type, SerializedObject serializedObject, string path)
{
return DrawEnum(type,serializedObject, GetPropety(serializedObject,path));
}
static public object DrawEnum(Type type, SerializedObject serializedObject,SerializedProperty property)
{
serializedObject.Update();
EditorGUILayout.PropertyField(property);
serializedObject.ApplyModifiedProperties();
return System.Enum.GetValues(type).GetValue(property.enumValueIndex);
}
static public SerializedProperty GetPropety(SerializedObject serializedObject, string path)
{
string []contents = path.Split('/');
SerializedProperty property = serializedObject.FindProperty(contents[0]);
for(int i=1; i< contents.Length; i++){
property = property.FindPropertyRelative(contents[i]);
}
return property;
}
}
#endif
使用是这样的,第二个参数就是排序。接收int的不固定参数。
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour
{
[EnumLabel("我是的类型",10,1,5,2)]
public NewType newType = NewType.One;
}
public enum NewType : byte
{
[EnumLabel("我是1")]
One = 10,
[EnumLabel("我是2")]
Two = 1,
[EnumLabel("我是3")]
Three = 5,
[EnumLabel("我是4")]
Four = 2
}
OK 中文与排序都OK了。
但是,有时候我们做编辑器的时候是自己调用OnInspectorGUI来绘制面板的。而且我的枚举对象可能会在另外一个子对象里,或者在子对象里的一个List<T>里面的子对象里。
比如这样, class.data.newType 就是这个类对象的结构,你可以按照你自己类的结构去拼这个字符串。
public override void OnInspectorGU()
{
NewType oldType = (NewType)EnumLabel.GetEnum(typeof(NewType),serializedObject,"class/data/newType");
NewType newType = (NewType)EnumLabel.DrawEnum(typeof(NewType),serializedObject,"class/data/newType");
if(oldType != newType)
{
//类型发生改变
}
}
还有一种特殊的就是可能枚举在list<T>里,这样在绘制的时候是需要遍历的。
public override void OnInspectorGU()
{
SerializedProperty property = EnumLabel.GetPropety(serializedObject,"class/datas");
for(int i =0; i< count; i++)
{
SerializedProperty eProperty = property.GetArrayElementAtIndex(i);
NewType newType = (NewType)EnumLabel.DrawEnum(typeof(NewType),serializedObject
,eProperty.FindPropertyRelative("newType"));
}
}
OK大功告成。
参考文章:
https://github.com/anchan828/property-drawer-collection/blob/master/EnumLabel/EnumLabelAttribute.cs
http://forum.unity3d.com/threads/enum-inspector-sorting-attribute.357558/
- 本文固定链接: https://www.xuanyusong.com/archives/4213
- 转载请注明: 雨松MOMO于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!


雨松大大,问个问题吗,有个需求是想在场景内的3D模型上显示一些UI信息,感觉UGUI的有些特性用2D的sprite无法完全表达,这个要咋个弄哦?
喔。。我好傻哦。。直接加个canvas就可以咯~~~~
哈哈
7月13日的,好新,充满希望!
新技能GET!
现在mmorpg手游的角色位置同步。应该传输摇杆的,还是坐标的信息到服务器去? 持续传还是出发传
其实都可以,但是我倾向客户端传输摇杆,比如摇杆一直朝着一个方向,就可以不用每一帧都发送。。
我也是这样想。去模拟摇杆还是比直接改位置好些,不然人可能都会跑地底下去
如果这样,那么后进入场景的玩家,怎么初始化已有玩家的位置信息,是个问题。服务器是不存玩家位置信息的,如果存,就要一直更新。现在想法是,进入时,服务器就把已有的人的位置信息请求一遍发给他,这样有延误。不知道有什么好的解决办法
服务器要存玩家位置。 回来的消息都是要带玩家的位置 如果客户端发现与服务器相差较大 直接拉回 采用服务器的位置。。
完成了。摇杆变化才会发送数据,对方接收到后以transform.Translate的方式移动。不过只有摇杆一直变化才能持续移动,又不愿在update里面写(如果没办法的话)。传统网游移动方式是什么
Get