热门标签 | 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保存一次。这样重进游戏数据就不会因为多态丢失了。


推荐阅读
  • andr ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
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社区 版权所有