使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据

效果展示

题集持久化数据:存储题目,可以直接在inspector面板上创建对应的问题子项

问题持久化数据

源码

ScriptableObject类

题集的持久化数据类

[CreateAssetMenu(fileName = "Config/Question/QuestionData",menuName = "题集数据")]
[Serializable]
public class ChoiceQuestionData: ScriptableObject
{
[SerializeField]
public List<ChoiceQuestionItem> Questions=new List<ChoiceQuestionItem>(); public ChoiceQuestionItem AddQuestion() {
ChoiceQuestionItem node = ScriptableObject.CreateInstance(typeof(ChoiceQuestionItem)) as ChoiceQuestionItem ;
Questions.Add(node);
return node;
} public void Clear() {
Questions.Clear();
}
}

问题的持久化数据

    [Serializable]
[CreateAssetMenu(fileName = "Config/Question/QuestionItem",menuName = "问题")]
public class ChoiceQuestionItem : ScriptableObject
{
[TextArea]
public string Question;
public List<string> Choices;
public List<int> RightOptions;
}
[Serializable]
[CreateAssetMenu(fileName = "Config/Question/QuestionItem",menuName = "问题")]
public class ChoiceQuestionItem : ScriptableObject
{
[TextArea]
public string Question;
public List<string> Choices;
public List<int> RightOptions;
}

题集的Editor脚本

 [CustomEditor(typeof(ChoiceQuestionData))]
public class ChoiceQuestionDataEditor: UnityEditor.Editor
{
private ChoiceQuestionData _choiceQuestionData;
private ReorderableList _questionReorderableList;
private SerializedProperty _questionProperty; private int _index;
private string _questionName;
public void OnEnable()
{
_choiceQuestionData = (ChoiceQuestionData)this.target;
_questionProperty = serializedObject.FindProperty("Questions");
_questionReorderableList = new ReorderableList(serializedObject, _questionProperty, true,true,true,true); //添加新元素时的回调函数,自定义新元素的值
_questionReorderableList.onAddCallback = list =>
{
if (list.serializedProperty != null)
{
var item = AddItem();
list.serializedProperty.arraySize++;
list.index = list.serializedProperty.arraySize - 1;
list.serializedProperty.GetArrayElementAtIndex(list.index)
.objectReferenceValue = item;
}
else
{
ReorderableList.defaultBehaviours.DoAddButton(list);
} }; //删除元素时的回调函数
_questionReorderableList.onRemoveCallback = list =>
{
RemoveItem(list.index);
ReorderableList.defaultBehaviours.DoRemoveButton(list);
};
} public override void OnInspectorGUI()
{
//更新序列化对象的表示形式。
serializedObject.Update(); //绘制列表头部,如标题等
_questionReorderableList.drawHeaderCallback = DrawHeaderCallback;
//绘制列表内部元素,缺少时面板不会显示具体元素的可赋值项,只会以Element+序号代替
_questionReorderableList.drawElementCallback = DrawElement;
//ReorderableList自动绘制
_questionReorderableList.DoLayoutList(); #region 添加问题 EditorGUILayout.BeginHorizontal();
_questionName = EditorGUILayout.TextField("问题名称", _questionName);
if (GUILayout.Button("添加问题", GUILayout.Height(15))) {
AddItem();
}
EditorGUILayout.EndHorizontal(); #endregion #region 删除问题 EditorGUILayout.BeginHorizontal();
_index = EditorGUILayout.IntField("索引", _index);
if (GUILayout.Button("删除", GUILayout.Height(15)))
{
if (_index > -1f && _index < _choiceQuestionData.Questions.Count)
{
AssetDatabase.RemoveObjectFromAsset(_choiceQuestionData.Questions[_index]);
_choiceQuestionData.Questions.RemoveAt(_index);
AssetDatabase.SaveAssets();
}
}
EditorGUILayout.EndHorizontal(); #endregion #region 清空问题 if (GUILayout.Button("清空", GUILayout.Height(20),GUILayout.Width(100))) {
var items = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_choiceQuestionData))
.Where(x=> x is ChoiceQuestionItem); foreach (var item in items)
{
AssetDatabase.RemoveObjectFromAsset(item);
}
this._choiceQuestionData.Clear(); AssetDatabase.SaveAssets();
}
#endregion //应用序列化对象的更改。
serializedObject.ApplyModifiedProperties();
} /// <summary>
/// 绘制列表头部
/// </summary>
/// <param name="rect"></param>
void DrawHeaderCallback(Rect rect)
{
GUI.Label(rect, "问题:");
Rect subChildRect = new Rect(rect.x + 80, rect.y, 150, rect.height);
GUI.Label(subChildRect, "【选项合集】");
} /// <summary>
/// 绘制列表内部元素
/// </summary>
void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
SerializedProperty element = _questionProperty.GetArrayElementAtIndex(index);
EditorGUI.PropertyField(rect, element);
} ChoiceQuestionItem AddItem()
{
var question=this._choiceQuestionData.AddQuestion();
question.name = _questionName??"QuestionItem";
//嵌套ChoiceQuestionItem的ScriptableObject到ChoiceQuestionData的ScriptableObject对象,方便归一到一个上层文件
AssetDatabase.AddObjectToAsset(question, target);
AssetDatabase.SaveAssets();
return question;
} void RemoveItem(int index)
{
AssetDatabase.RemoveObjectFromAsset(this._choiceQuestionData.Questions[index]);
this._choiceQuestionData.Questions.RemoveAt(index);
AssetDatabase.SaveAssets();
}

参考

  1. Unity编辑器拓展之二:ReorderableList可重新排序的列表框(复杂使用)

  2. Unity 编辑器扩展总结 七:数组或list集合的显示方式

使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据的更多相关文章

  1. 使用Entity Framework通过code first方式创建数据库和数据表

    开发环境 WIN10 Entity Framework6.0  MVC5.0  开发工具 VS2015  SqlServer2012 1.创建上下文Context继承DbContext,并创建其他的业 ...

  2. 创建ACCESS数据库,并且创建表和数据。重点:关闭ACCESS数据库引用

    /// <summary> /// 创建ACCESS数据库,并且创建表和数据 /// </summary> /// <param name="dictTable ...

  3. sql server2008中怎样用sql语句创建数据库和数据表

    这是简单用代码实现创建数据库和数据表的sql语句,如下: --调用系统数据库-- use master go /***防止你要创建的数据库同名,先把它删除掉****/ if Exists(select ...

  4. 在ArcMap 10.3中创建和编辑数据

    在ArcMap 10.3中创建和编辑数据 .......待补充 新建 创建一个新文件((Points, Polylines, and Polygons/点.线.多边形)

  5. WordPress插件制作教程(五): 创建新的数据表

    上一篇讲解了怎样将数据保存到数据库,今天为大家讲解创建新的数据表,也就是说当我们激活插件的时候,会在该数据库下面创建一个新的数据表出来.原理很简单,激活插件的时候运行创建数据库的代码.看下面代码: & ...

  6. 如何创建一个要素数据类 IField,IFieldEdit,IFields,IFieldsEditI,GeometryDef,IGeometryDefEdit接口

    如何创建一个要素数据类 创建要素类用到了IFeatureWorkspace.CreateFeatureClass方法,在这个方法中有众多的参数,为了满足这些参数,我们要学习和了解下面的接口. IFie ...

  7. 根据dateFormatter创建NSDate类型数据

    根据dateFormatter 2000-01-01 创建NSDate类型数据 NSDateFormatter *dateFormatter = [NSDate shareDateFormatter] ...

  8. Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定

    Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定 创建 angular 组件 https://github.com/angular/angular- ...

  9. C# 利用mysql.data 在mysql中创建数据库及数据表

    C# 利用mysql.data 在mysql中创建数据库及数据表 using System; using System.Collections.Generic; using System.Linq; ...

  10. 快速创建显示数字数据的动画——CountUp.js

    由于项目需求,需要写一个数字增/减量的动画特效,最后找到了CountUp.js CountUp.js是一个无依赖,轻量级的JavaScript“类”,可用于快速创建以更有趣的方式显示数字数据的动画. ...

随机推荐

  1. 记 Win8.1 某应用渲染抛出 OutOfMemoryException 异常及修复方法

    本文记录某个应用在某台 Windows 8.1 x86 系统上,运行时抛出 OutOfMemoryException 异常,启动失败.应用程序能启动,但是在第一次碰到渲染时,就发现渲染初始化失败,从而 ...

  2. dotnet OpenXML 继承组合颜色的 GrpFill 属性

    在 OpenXML 的颜色画刷填充,有特殊的填充是 GrpFill 属性,对应 OpenXML SDK 定义的 DocumentFormat.OpenXml.Drawing.GroupFill 类型 ...

  3. MQTT GUI 客户端 可视化管理工具

    MQTT GUI 客户端 可视化管理工具 介绍 多标签页管理,同时打开多个连接 提供原生性能,并且比使用 Electron 等 Web 技术开发的同等应用程序消耗的资源少得多 支持 MQTT v5.0 ...

  4. vue全国省市选择vue组件

    没用懂checkbox,干脆自己定义布尔值,方便数据页面响应. 可以再原始省市数据 下载address.js文件 1.初始化数据格式: 2页面样式: 3.对应输出的数据格式: 4.源码: <!D ...

  5. 小程序中使用 lottie 动画 | 踩坑经验分享

    最近被拉去支援紧急需求(赶在五一节假日前上线的,双休需要加班),参与到项目中才知道,开发的项目是微信小程序技术栈的.由于是临时支援,笔者也很久没开发过微信小程序了,所以挑选了相对独立,业务属性相对轻薄 ...

  6. WebStorm2023安装prettier并生效

    1.首先去File > Settings > Plugins 里下载并install插件 Prettier 2.在settings里搜索prettier,按图片所示设置一下Apply 3. ...

  7. Zookeeper中的角色

    在zookeeper集群中,节点也有不同的角色,承担着不同角色. zookeeper有三种角色: 老大:Leader   (领导者)   : 客户端提供读服务和写服务. 老二:Follower(跟随者 ...

  8. PostgreSQL世界上最先进的开源关系型数据库

    PostgreSQL 的 Slogan 是 "世界上最先进的开源关系型数据库". PostgreSQL是一个功能非常强大.源代码开放的对象关系数据库系统(ORDBMS),在灵活的B ...

  9. python教程8-页面爬虫

    python爬虫常用requests和beautifulSoup这2个第三方模块.需要先进行手动安装. requests负责下载页面数据,beautifulSoup负责解析页面标签. 关于beauti ...

  10. ctf_web

    ctfshow web13 访问题目链接 一看是一道文件上传题,上传文件进行测试 上传php会显示 error suffix 因此推测会检测格式 当文件字数超出一定字数时,显示 error file ...