使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据
使用嵌套的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();
}
参考
使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据的更多相关文章
- 使用Entity Framework通过code first方式创建数据库和数据表
开发环境 WIN10 Entity Framework6.0 MVC5.0 开发工具 VS2015 SqlServer2012 1.创建上下文Context继承DbContext,并创建其他的业 ...
- 创建ACCESS数据库,并且创建表和数据。重点:关闭ACCESS数据库引用
/// <summary> /// 创建ACCESS数据库,并且创建表和数据 /// </summary> /// <param name="dictTable ...
- sql server2008中怎样用sql语句创建数据库和数据表
这是简单用代码实现创建数据库和数据表的sql语句,如下: --调用系统数据库-- use master go /***防止你要创建的数据库同名,先把它删除掉****/ if Exists(select ...
- 在ArcMap 10.3中创建和编辑数据
在ArcMap 10.3中创建和编辑数据 .......待补充 新建 创建一个新文件((Points, Polylines, and Polygons/点.线.多边形)
- WordPress插件制作教程(五): 创建新的数据表
上一篇讲解了怎样将数据保存到数据库,今天为大家讲解创建新的数据表,也就是说当我们激活插件的时候,会在该数据库下面创建一个新的数据表出来.原理很简单,激活插件的时候运行创建数据库的代码.看下面代码: & ...
- 如何创建一个要素数据类 IField,IFieldEdit,IFields,IFieldsEditI,GeometryDef,IGeometryDefEdit接口
如何创建一个要素数据类 创建要素类用到了IFeatureWorkspace.CreateFeatureClass方法,在这个方法中有众多的参数,为了满足这些参数,我们要学习和了解下面的接口. IFie ...
- 根据dateFormatter创建NSDate类型数据
根据dateFormatter 2000-01-01 创建NSDate类型数据 NSDateFormatter *dateFormatter = [NSDate shareDateFormatter] ...
- Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定
Angular4.x 创建组件|绑定数据|绑定属性|数据循环|条件判断|事件|表单处理|双向数据绑定 创建 angular 组件 https://github.com/angular/angular- ...
- C# 利用mysql.data 在mysql中创建数据库及数据表
C# 利用mysql.data 在mysql中创建数据库及数据表 using System; using System.Collections.Generic; using System.Linq; ...
- 快速创建显示数字数据的动画——CountUp.js
由于项目需求,需要写一个数字增/减量的动画特效,最后找到了CountUp.js CountUp.js是一个无依赖,轻量级的JavaScript“类”,可用于快速创建以更有趣的方式显示数字数据的动画. ...
随机推荐
- Apache Flink 在京东的实践与优化
简介: Flink 助力京东实时计算平台朝着批流一体的方向演进. 本文整理自京东高级技术专家付海涛在 Flink Forward Asia 2020 分享的议题<Apache Flink 在京 ...
- [FAQ] "cannot refer to unexported name" in Golang ?
Golang 项目中如果使用了其它模块中找不到的函数.常量等,都会提示 "cannot refer to unexported name". 遇到这种情况,要么是拼写错误了,要么是 ...
- Go-Zero微服务快速入门和最佳实践(一)
前言 并发编程和分布式微服务是我们Gopher升职加薪的关键. 毕竟Go基础很容易搞定,不管你是否有编程经验,都可以比较快速的入门Go语言进行简单项目的开发. 虽说好上手,但是想和别人拉开差距,提高自 ...
- python3解析FreeSWITCH会议室列表信息
操作系统 :CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 Python版本:3.9.12 进行FreeSWITCH会议室相关功能开发过程中,会遇到需要解析会议室列表信息并进行 ...
- Blazor/Hybird 触屏下单程序调优笔记
环境 Blazor Net8.0 + FreeSql + Bootstrap Blazor 组件 以下都是自己瞎琢磨的和官网资料搬运,肯定有不少错漏和不合理的地方,非常希望各位大佬评论区给我建议和意见 ...
- go1.18泛型全部教程
目录 go1.18泛型全部教程 一 什么是泛型 二 Golang中的泛型 三 泛型语法详解 3.1 泛型的语法 3.2 Constraint(约束)是什么 3.3 自定义constraint(约束) ...
- Go语言基础之并发 goroutine chan
参考文档: https://www.liwenzhou.com/posts/Go/14_concurrence/ http://www.5lmh.com/并发编程/channel.html 示例一: ...
- springboot 整合 recketMQ 详细步骤
前提 RocketMQ的部署环境可用 1 依赖包 <dependency> <groupId>org.apache.rocketmq</groupId> <a ...
- 将任意程序安装成windows服务
某些时候,一个程序控制台服务程序需要在系统启动的时候自动运行,这时候我们会想到采用windows服务的方式来实现 但是,如果程序本来不支持安装成服务的话,我就需要采用其他方案来实现 之前博主也遇到了类 ...
- 莫烦tensorflow学习记录 (7)循环神经网络 RNN & LSTM
莫凡大佬的原文章https://mofanpy.com/tutorials/machine-learning/tensorflow/intro-RNN/ RNN 的用途 可以读取数据中的顺序,获取顺序 ...