热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

U3d属性面板自定义扩展(多态数组)

原文地址:https:blog.csdn.netqq_35361471articledetails84715491原文地址:https:blog.cs

序列化相关问题:https://blog.uwa4d.com/archives/2025.html

一直想研究,怎么使用 ScriptableObject 来存储多态数组,目前U3d 中序列化是不允许的。


第一种尝试

思想:把多态类型的基类继承自ScriptableObject ,然后属性面板界面自己实现:

[Serializable]
public class StoryEffect:ScriptableObject
{protected string _Name = "StoryEffect";protected string _EffectBasePath = "StoryNode/StoryCanvas/";[SerializeField]protected StorySegment.StoryState _ExecState = StorySegment.StoryState.NONE;private bool _IsPlaying = false;public bool IsPlaying {get { return _IsPlaying; }}public StorySegment.StoryState ExecState{get { return _ExecState; }}public string Name{get { return _Name; }}public virtual IEnumerator Init(){Debug.Log("StoryEffect:Init______________________");yield return null;}public virtual IEnumerator Play(){Debug.Log("StoryEffect:Play______________________");_IsPlaying = true;yield return null;}}public class StorySegment : ScriptableObject,IStorySegment
{public enum StoryState{NOnE= 0,START = 1,DOING = 2,END = 3,}[SerializeField]private int _ID = 0;[SerializeField]private List _StoryEffectList = new List();private StoryState _CurState = StoryState.NONE;private bool _IsEnd = false;}public override void OnInspectorGUI(){serializedObject.Update();// 绘制全部原有属性//base.DrawDefaultInspector();//重绘数组界面EditorGUILayout.PropertyField(this.serializedObject.FindProperty("_ID"), true);_expand = EditorGUILayout.Foldout(_expand, "StoryEffectList");if (_expand){EditorGUI.indentLevel++;for (int i = 0; i <_target.GetStoryEffectCount(); ++i){var ttt = _target.GetStoryEffectByIndex(i);var subopen = false;if (!_subExpand.TryGetValue(i, out subopen)){subopen = false;}GUILayout.BeginHorizontal();if (GUILayout.Button("删", GUILayout.Width(20), GUILayout.Height(20))){_target.RemoveStoryEffectByIndex(i);return;}_subExpand[i] = EditorGUILayout.Foldout(subopen, ttt.Name);GUILayout.EndHorizontal();if (subopen){EditorGUI.indentLevel++;Type t = ttt.GetType();FieldInfo[] fieldInfos = t.GetFields(BindingFlags.Instance|BindingFlags.Static | BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Default);//Debug.Log("fieldName------>" +fieldInfos.Length);PropertyInfo[] ps = t.GetProperties(BindingFlags.Instance|BindingFlags.Static | BindingFlags.Public|BindingFlags.DeclaredOnly);foreach (var p in ps){string pName = p.Name;string pType = p.PropertyType.ToString();object pValue = p.GetValue(ttt,null);if (p.CanWrite){DisStoryEffectPropertyInfo(pName, pType, pValue, p, ttt);}}foreach (var f in fieldInfos){//字段名称string fieldName = f.Name;//字段类型string fieldType = f.FieldType.ToString();//字段的值object fieldValue = f.GetValue(ttt);if (f.GetCustomAttributes(typeof(SerializeField), true).Length > 0){DisStoryEffectFieldInfo(fieldName, fieldType, fieldValue, f, ttt);}// Debug.Log("fieldName------>" + fieldName );
// Debug.Log( "fieldType------>" + fieldType );}EditorGUI.indentLevel--;}}EditorGUI.indentLevel--;}// 自定义绘制Inspectorif (GUILayout.Button("添加效果", GUILayout.Height(30))){if (_SelectWindow == null){_SelectWindow = new StoryEffectSelectWindow();}_SelectWindow.SetSelectHandle((string name) =>{StorySegment node = (StorySegment) target;var temp = StoryEffectFactory.CreateEffect(name);Type type = temp.GetType();node.AddStoryEffect(temp); });_SelectWindow.title = "Select StoryEffect";_SelectWindow.Show();_SelectWindow.maxSize = new Vector2(500,500);_SelectWindow.minSize = _SelectWindow.maxSize;var position = _SelectWindow.position;position.center = new Rect (0f, 0f, Screen.currentResolution.width, Screen.currentResolution.height).center;_SelectWindow.position = position;}this.serializedObject.ApplyModifiedProperties();}

上面省略了非关键代码。这样做,在允许和设置都没有问题。但是在关闭编辑器,重新进来的时候,添加的StoryEffect会直接删除掉。尝试失败。


第二种尝试

上面不能保存是数据是由于不支持的序列化类型导致的,没法保存到ScriptableObject,那好吧,只能绕个道了。创建一个数据类型,里面通过把自定义类反射获得变量属性,然后存到这个数据类中,序列化中就存类的属性值,在要使用这个值的时候动态创建自定义类型。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityScript.Macros;
using Object = System.Object;[Serializable]
public class StoryData
{[SerializeField]public string ClassName;[SerializeField]public List FiledNames = new List();[SerializeField]public List FiledTypes= new List();[SerializeField]public List FiledStringValues = new List();[SerializeField]public List FiledIntValues = new List();[SerializeField]public List FiledFloatValues = new List();[SerializeField]public List FiledBoolValues = new List();[SerializeField]public List FiledObjectValues = new List();[SerializeField]private List FiledIndexList = new List();[SerializeField]public List PrOnames= new List();[SerializeField]public List ProTypes= new List();[SerializeField]public List ProStringValues = new List();[SerializeField]public List ProIntValues = new List();[SerializeField]public List ProFloatValues = new List();[SerializeField]public List ProBoolValues = new List();[SerializeField]public List ProObjectValues = new List();[SerializeField]private List ProIndexList = new List();public void AddFiled(string name, string type, Object value){FiledNames.Add(name);FiledTypes.Add(type);if (type == "System.String"){FiledIndexList.Add(FiledNames.Count - 1);FiledIndexList.Add(FiledStringValues.Count);string v = "";if (value!= null){v = (string)value;}FiledStringValues.Add(v);}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){FiledIndexList.Add(FiledNames.Count - 1);FiledIndexList.Add(FiledIntValues.Count);int v = 0;if (value != null){v = (int)value;}FiledIntValues.Add(v);}else if (type == "System.Single"){FiledIndexList.Add(FiledNames.Count - 1);FiledIndexList.Add(FiledFloatValues.Count);float v = 0;if (value != null){v = (float)value;}FiledFloatValues.Add(v);}else if (type == "System.Boolean"){FiledIndexList.Add(FiledNames.Count - 1);FiledIndexList.Add(FiledBoolValues.Count);bool v = false;if (value != null){v = (bool)value;}FiledBoolValues.Add(v);}else{FiledIndexList.Add(FiledNames.Count - 1);FiledIndexList.Add(FiledObjectValues.Count);GameObject v = null;if (value != null){v = (GameObject) value;}FiledObjectValues.Add(v);} }public void SetFiledValue(int index,Object value){string type = FiledTypes[index];int vIndex = -1;for (int i = 0; i = 0){if (type == "System.String"){string v = "";if (value!= null){v = (string)value;}FiledStringValues[vIndex] = v;}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){int v = 0;if (value!= null){v = (int)value;}FiledIntValues[vIndex] = v;}else if (type == "System.Single"){float v = 0;if (value!= null){v = (float)value;}FiledFloatValues[vIndex] = v;}else if (type == "System.Boolean"){bool v = false;if (value!= null){v = (bool)value;}FiledBoolValues[vIndex] = v;}else{UnityEngine.Object v = null;if (value!= null){v = (UnityEngine.Object)value;}FiledObjectValues[vIndex] = v;} }}public object GetFiledValue(int index){string type = FiledTypes[index];int vIndex = -1;for (int i = 0; i = 0){if (type == "System.String"){return FiledStringValues[vIndex] ;}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){return FiledIntValues[vIndex];}else if (type == "System.Single"){return FiledFloatValues[vIndex] ;}else if (type == "System.Boolean"){return FiledBoolValues[vIndex];}else{return FiledObjectValues[vIndex];} }return null;}public void AddPro(string name, string type, Object value){ProNames.Add(name);ProTypes.Add(type);if (type == "System.String"){ProIndexList.Add(ProNames.Count - 1);ProIndexList.Add(ProStringValues.Count);string v = "";if (value!= null){v = (string)value;}ProStringValues.Add(v);}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){ProIndexList.Add(ProNames.Count - 1);ProIndexList.Add(ProIntValues.Count);int v = 0;if (value != null){v = (int)value;}ProIntValues.Add(v);}else if (type == "System.Single"){ProIndexList.Add(ProNames.Count - 1);ProIndexList.Add(ProFloatValues.Count);float v = 0;if (value != null){v = (float)value;}ProFloatValues.Add(v);}else if (type == "System.Boolean"){ProIndexList.Add(ProNames.Count - 1);ProIndexList.Add(ProBoolValues.Count);bool v = false;if (value != null){v = (bool)value;}ProBoolValues.Add(v);}else{ProIndexList.Add(ProNames.Count - 1);ProIndexList.Add(ProObjectValues.Count);UnityEngine.Object v = null;if (value != null){v = (UnityEngine.Object) value;}ProObjectValues.Add(v);} }public void SetProValue(int index,Object value){string type = ProTypes[index];int vIndex = -1;for (int i = 0; i = 0){if (type == "System.String"){string v = "";if (value!= null){v = (string)value;}ProStringValues[vIndex] = v;}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){int v = 0;if (value!= null){v = (int)value;}ProIntValues[vIndex] = v;}else if (type == "System.Single"){float v = 0;if (value!= null){v = (float)value;}ProFloatValues[vIndex] = v;}else if (type == "System.Boolean"){bool v = false;if (value!= null){v = (bool)value;}ProBoolValues[vIndex] = v;}else{UnityEngine.Object v = null;if (value!= null){v = (UnityEngine.Object)value;}ProObjectValues[vIndex] = v;} }}public object GetProValue(int index){string type = ProTypes[index];int vIndex = -1;for (int i = 0; i = 0){if (type == "System.String"){return ProStringValues[vIndex] ;}else if (type == "System.Int32" ||type == "StorySegment+StoryState"){return ProIntValues[vIndex];}else if (type == "System.Single"){return ProFloatValues[vIndex] ;}else if (type == "System.Boolean"){return ProBoolValues[vIndex];}else{return ProObjectValues[vIndex];} }return null;}}

这样就把多态类型通过反射,把变量值保存在里面

public class StorySegment : ScriptableObject,IStorySegment
{public enum StoryState{NOnE= 0,START = 1,DOING = 2,END = 3,}[SerializeField]private int _ID = 0;[SerializeField]private List _StoryEffectList = new List();
}

这样我们使用StoryData的类型作为序列化。

然后创建代码:

foreach (StoryData it in _StoryEffectList){StoryEffect effet = StoryEffectFactory.CreateEffect(it.ClassName,it);if (effet.ExecState == state && !effet.IsPlaying){doList.Add(effet);Debug.Log("_______________________________________________PlayEffect:init");yield return effet.Init();}}

然后我们自定义 StorySegment的属性面板,这样就可以变成自已想要的布局效果。

public override void OnInspectorGUI(){serializedObject.Update();// 绘制全部原有属性// base.DrawDefaultInspector();//重绘数组界面EditorGUILayout.PropertyField(this.serializedObject.FindProperty("_ID"), true);_expand = EditorGUILayout.Foldout(_expand, "StoryEffectList"+"("+_target.GetStoryEffectCount()+")");if (_expand){EditorGUI.indentLevel++;for (int i = 0; i <_target.GetStoryEffectCount(); ++i){var ttt = _target.GetStoryEffectByIndex(i);var subopen = false;if (!_subExpand.TryGetValue(i, out subopen)){subopen = false;}GUILayout.BeginHorizontal();if (GUILayout.Button("删", GUILayout.Width(20), GUILayout.Height(20))){_target.RemoveStoryEffectByIndex(i);return;}_subExpand[i] = EditorGUILayout.Foldout(subopen, ttt.ClassName);GUILayout.EndHorizontal();if (subopen){EditorGUI.indentLevel++;for(int j = 0; j {var temp = StoryEffectFactory.CreateEffect(name);StoryData data = new StoryData();data.ClassName = name;Type t = temp.GetType();FieldInfo[] fieldInfos = t.GetFields(BindingFlags.Instance|BindingFlags.Static | BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Default);//Debug.Log("fieldName------>" +fieldInfos.Length);PropertyInfo[] ps = t.GetProperties(BindingFlags.Instance|BindingFlags.Static | BindingFlags.Public|BindingFlags.DeclaredOnly);foreach (var p in ps){string pName = p.Name;string pType = p.PropertyType.ToString();object pValue = p.GetValue(temp,null);if (p.CanWrite){data.AddPro(pName,pType,pValue);}}foreach (var f in fieldInfos){//字段名称string fieldName = f.Name;//字段类型string fieldType = f.FieldType.ToString();//字段的值object fieldValue = f.GetValue(temp);if (f.GetCustomAttributes(typeof(SerializeField), true).Length > 0){data.AddFiled(fieldName,fieldType,fieldValue);}}_target.AddStoryEffect(data); });_SelectWindow.title = "Select StoryEffect";_SelectWindow.Show();_SelectWindow.maxSize = new Vector2(500,500);_SelectWindow.minSize = _SelectWindow.maxSize;var position = _SelectWindow.position;position.center = new Rect (0f, 0f, Screen.currentResolution.width, Screen.currentResolution.height).center;_SelectWindow.position = position;}if (GUILayout.Button("保存", GUILayout.Height(30))){EditorUtility.SetDirty(_target);}this.serializedObject.ApplyModifiedProperties();}

注意:EditorGUILayout.PropertyField这种显示界面是能够修改后保存,如果我们自己代码修改,或者通过自己添加的文本框等界面对序列化对象赋值是不会保存在磁盘的,在下次进来就会丢失掉。所以我加了个保存,里面:

EditorUtility.SetDirty(_target);

就对当前的ScriptableObject保存一次。这样重进游戏数据就不会因为多态丢失了。


推荐阅读
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • 序列化与反序列化是数据处理中的重要技术,特别是在网络通信和数据存储中。它们允许将复杂的数据结构转换为可传输或存储的格式,再从这些格式恢复原始数据。本文探讨了序列化与反序列化的基本概念,以及它们在不同协议模型中的角色。 ... [详细]
  • 本文深入探讨了MySQL中常见的面试问题,包括事务隔离级别、存储引擎选择、索引结构及优化等关键知识点。通过详细解析,帮助读者在面对BAT等大厂面试时更加从容。 ... [详细]
  • 本文介绍了如何在iOS应用中自定义导航栏按钮,包括使用普通按钮和图片生成导航条专用按钮的方法。同时,探讨了在不同版本的iOS系统中实现多按钮布局的技术方案。 ... [详细]
  • 本文深入探讨了 Delphi 中类对象成员的核心概念,包括 System 单元的基础知识、TObject 类的定义及其方法、TClass 的作用以及对象的消息处理机制。文章不仅解释了这些概念的基本原理,还提供了丰富的补充和专业解答,帮助读者全面理解 Delphi 的面向对象编程。 ... [详细]
  • 请看|间隔时间_Postgresql 主从复制 ... [详细]
  • 本文探讨了Web开发与游戏开发之间的主要区别,旨在帮助开发者更好地理解两种开发领域的特性和需求。文章基于作者的实际经验和网络资料整理而成。 ... [详细]
  • MongoDB的核心特性与架构解析
    本文深入探讨了MongoDB的核心特性,包括其强大的查询语言、灵活的文档模型以及高效的索引机制。此外,还详细介绍了MongoDB的体系结构,解释了其文档、集合和数据库的层次关系,并对比了MongoDB与传统关系型数据库(如MySQL)的逻辑结构。 ... [详细]
  • 本文详细介绍了如何使用 HTML 和 CSS 对文件上传按钮进行样式美化,使用户界面更加友好和美观。 ... [详细]
  • 使用WinForms 实现 RabbitMQ RPC 示例
    本文通过两个WinForms应用程序演示了如何使用RabbitMQ实现远程过程调用(RPC)。一个应用作为客户端发送请求,另一个应用作为服务端处理请求并返回响应。 ... [详细]
  • iOS 开发技巧:TabBarController 自定义与本地通知设置
    本文介绍了如何在 iOS 中自定义 TabBarController 的背景颜色和选中项的颜色,以及如何使用本地通知设置应用程序图标上的提醒个数。通过这些技巧,可以提升应用的用户体验。 ... [详细]
  • 本文探讨了如何使用pg-promise库在PostgreSQL中高效地批量插入多条记录,包括通过事务和单一查询两种方法。 ... [详细]
  • Win10 UWP 开发技巧:利用 XamlTreeDump 获取 XAML 元素树
    本文介绍如何在 Win10 UWP 开发中使用 XamlTreeDump 库来获取和转换 XAML 元素树为 JSON 字符串,这对于 UI 单元测试非常有用。 ... [详细]
  • 本文详细介绍了Java集合框架中的Collection体系,包括集合的基本概念及其与数组的区别。同时,深入探讨了Comparable和Comparator接口的区别,并分析了各种集合类的底层数据结构。最后,提供了如何根据需求选择合适的集合类的指导。 ... [详细]
  • 深入理解String.Format()方法的应用
    在.NET框架中,String.Format()方法是一种非常实用的工具,它能够帮助开发者以灵活多样的方式格式化字符串。本文将通过一个具体的示例,详细介绍如何利用String.Format()方法处理数值、日期时间和枚举类型的格式化。 ... [详细]
author-avatar
韩铁衣
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有