首页 > 其他分享 >使用嵌套的ScriptableObject及ReorderableList创建习题持久化数据

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

时间:2023-01-05 17:46:55浏览次数:61  
标签:index ScriptableObject list public AssetDatabase 习题 choiceQuestionData Reorderab

使用嵌套的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集合的显示方式

标签:index,ScriptableObject,list,public,AssetDatabase,习题,choiceQuestionData,Reorderab
From: https://www.cnblogs.com/Firepad-magic/p/17028371.html

相关文章

  • 天梯赛练习题L2(021-025)
    L2-021点赞狂魔如果有并列,则输出标签出现次数平均值最小的那个#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<LL,LL>PII;const......
  • 习题2.5 两个有序链表序列的合并 (15 分)
    本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。函数接口定义:ListMerge(ListL1,ListL2);其中List结构定义如下:typedefstructNode......
  • 天梯赛练习题L2(016-020)
    L2-016愿天下有情人都是失散多年的兄妹这题一开始我没有标注爸爸妈妈是男的是女的直接卡了半天#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;t......
  • HDLBits--Verilog习题记录5
    此题目较难,本文代码也是借鉴别人才完全理解。题目编号:verification:readingsimulations->buildacircuitfromasimulationwaveform->sequentialcircuit10题目描述......
  • 天梯赛练习题L2(011-015)
    L2-011玩转二叉树#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;typedefpair<LL,LL>PII;constLLMAXN=1e18;constLLN=500200,M=4002;//u......
  • 周志华《机器学习》课后习题(第三章):线性模型
    作者| 我是韩小琦3.1试分析在什么情况下,在以下式子中不比考虑偏置项b。答:在样本  中有某一个属性  为固定值时。那么此时  等价于偏置项,此时  与  等价。3.2......
  • 周志华《机器学习》课后习题(第六章):支持向量机
    作者| 我是韩小琦6.1试证明样本空间中任意点  到超平面  的的距离为式(6.2)。答:图中,令A点到超平面(点B)的距离为 ,于是  (  是  同向的单位向量,对于超平面 其......
  • HDLBits--Verilog习题记录4
    4.Circuits---SequentialLogic---LatchesandFlip-Flops----Edgecaptureregister问题描述:Foreachbitina32-bitvector,capturewhentheinputsignalchanges......
  • HDLBits--Verilog习题记录3
    3.Circuits---SequentialLogic---LatchesandFlip-Flops----Detectanedge问题描述:Foreachbitinan8-bitvector,detectwhentheinputsignalchangesfrom0......
  • 【MATLAB习题】双摇杆机构的运动学分析
    1.双摇杆机构概述双摇杆机构的判别方法:最长杆长度+最短杆长度≤其他两杆长度之和,连杆(机架的对杆)为最短杆时。如果最长杆长度+最短杆长度>其他两杆长度之和,......