使用嵌套的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. 5分钟搞定AlertManager接入短信、语音等10+种通知渠道

    ​简介: Alert Manager是开源监控系统Prometheus中用于处理告警信息的服务,通过将日志服务开放告警配置为Alert Manager中的一个Receiver,可以将Alert Man ...

  2. dotnet 在 WPF 里显示数学 π 的颜色

    有逗比小伙伴问我,数学的 π 视觉效果是啥.于是我就来写一个逗比的应用将 π 的颜色在 WPF 应用画出来.原理就是读取 π 的小数点后的数值,然后使用逗比算法转换为 RGB 颜色像素,接着将这些像素 ...

  3. Win10下小米路由器4A百兆版刷Openwrt固件【图片详细版】

    将原来的小米路由器换成了华为,早就听闻刷软路由可以实现去广告,解锁灰色歌单等诸多骚操作.就来榨取这个小米4A的剩余价值来着的. 注意 1. 必须使用路由模式,中继模式是打不开telnet的 更新固件 ...

  4. vue引入一个单独的数据文件

    1.新建一个address.js的文件 2.文件内const citys = { "北京市":         ["东城区","西城区",& ...

  5. Listener监听器,实现一个显示在线用户人数

    Listener监听器,实现一个显示在线用户人数 每博一文案 关于后半身,脾气越温,福报越深. 师傅说:惜命最好的方式不是养生,而是管好自己的情绪. 坏毛病都是惯出来的,但好脾气都是磨出来的,与人生气 ...

  6. 【简说Python WEB】Form提交表单

    目录 [简说Python WEB]Form提交表单 安装flask-wtf 代码树 app.py源码中表单类: index.html的源码修改:渲染form表单 app.py源码中from表单处理 会 ...

  7. 前端scale负数表示翻转

    https://blog.csdn.net/wang_yu_shun/article/details/121299208 极力推荐这个博主写的,前端有关负数的小技巧

  8. 腾讯、阿里、B站最新面经汇总,有的妥妥的凉经。

    除了BAT(没错我说的B是B站的B),还有网易.希音科技.美柚等中小厂的最新面经. 这次投稿的同学行文幽默风趣,处处透漏着不成功便搞笑的骚气. 祝他早日上岸,也欢迎大家在评论区讨论这些面试题,有哪些面 ...

  9. go高并发之路——go语言如何解决并发问题

    一.选择GO的原因 作为一个后端开发,日常工作中接触最多的两门语言就是PHP和GO了.无可否认,PHP确实是最好的语言(手动狗头哈哈),写起来真的很舒爽,没有任何心智负担,字符串和整型压根就不用区分, ...

  10. Base64 java图片工具类

    import org.springframework.util.Assert; import javax.imageio.ImageIO; import java.awt.image.Buffered ...