当前位置:   article > 正文

unity——ScriptableObject相关知识点【学习笔记/不足之处欢迎斧正/个人复习向/侵删】

scriptableobject

一、相关简介

1.ScriptableObject是什么:Unity提供的一个数据存储基类

2.ScriptableObject的好处有哪些:文件配置、数据复用、更好的处理数据带来的多态性为

二、ScriptableObject的创建

1.自定义ScriptableOject数据容器

        继承ScriptableObject类

        在该类中声明成员(变量、方法等)

  1. public class StudyUnity : ScriptableObject
  2. {
  3. //可以在其中声明任何一种类型的变量,
  4. //如果想要在Inspector窗口中能够编辑它,那么
  5. //声明变量的规则应该与MonoBehavior的public变量规则相同
  6. public bool a;
  7. public float b;
  8. public GameObject c;
  9. public Material d;
  10. }

        通过这种方式,我们能在Inspector窗口中看到变化,其中数据的关联信息是通过脚本文件unity配置的meta文件进行记录的,之后我们可以利用他的信息创建对应的数据资源文件

2.根据自定义ScriptableObject数据容器创建数据文件

本质上是根据自定义数据容器类创建了一个配置文件,该文件中记录了对应的数据容器类信息,以及其中变量关联的信息,我们在使用的过程中,本质上也是通过反射创建对象进行使用的

具体的方式有两种:

        1.为类添加CreateAssetMenu通过菜单创建资源特性:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. [CreateAssetMenu(fileName ="a文件",menuName ="b菜单",order =0)]
  5. public class StudyUnity : ScriptableObject
  6. {
  7. //可以在其中声明任何一种类型的变量,
  8. //如果想要在Inspector窗口中能够编辑它,那么
  9. //声明变量的规则应该与MonoBehavior的public变量规则相同
  10. public bool a;
  11. public float b;
  12. public GameObject c;
  13. public Material d;
  14. }

这时我们回到unity可以看到

        2.利用ScriptableObject的静态方法创建数据对象,之后将数据对象保存在工程目录下:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. public class Study2
  6. {
  7. [MenuItem("a/Tostudy")]
  8. //using UnityEditor;
  9. public static void ToStudy()
  10. {
  11. }
  12. }

在此之后,回到unity中我们可以看到:

我们只需要在静态函数中数次额创建资源文件的代码即可

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. public class Study2
  6. {
  7. [MenuItem("a/ToStudy")]
  8. //using UnityEditor;
  9. public static void ToStudy()
  10. {
  11. StudyUnity s=ScriptableObject.CreateInstance<StudyUnity>();
  12. //通过编译器API,可以根据数据创建一个数据资源文件
  13. AssetDatabase.CreateAsset(s, "Assets/Studt2data.asset");
  14. //在Assets路径下创建Studt2data.asset
  15. //保存创建的资源
  16. AssetDatabase.SaveAssets();
  17. //刷新界面
  18. AssetDatabase.Refresh();
  19. }
  20. }

3.使用ScriptableObject的好处体现在哪里?

        可以更方便的配置数据,可以直接在Inspector中进行数据的配置

        可以在项目之间进行复用,可以拷贝继承ScriptableObject的脚本到任何工程之中

三、ScriptableObject数据文件

        1.ScriptableObject如何使用:

                通过Inspector窗口中的public变量进行关联:可以用上述方法创建数据文件,同时在继承MonoBehaviour类中申明数据容器类型的成员,最后在Inspector窗口中进行关联

                通过资源加载的信息关联:加载数据文件资源,需要注意的是,Resources\AB包、Addressables都支持加载继承ScriptableObject的数据文件(如果同时有多个对象关联同一个数据容器文件,他们贡献的是一个对象,因为是引用对象,所以在任何地方进行修改后,其他地方也会发生改变)

        2.ScriptableObject的生命周期函数

                类似于MonoBehavior,但是ScriptableObject的生命周期函数更少

                Awake 数据文件创建时调用

                OnDestroy对象将要被销毁时调用

                OnDisable对象销毁时,即将重新把加载脚本程序集时调用

                OnEnable创建或者加载对象时调用

                Onvalidate 编译器才会进行调用的生命周期函数,Unity在加载脚本或者Inspector窗口中更改值时调用

        3.使用的好处:

                通过代码修改对象中的内容后,会影响到数据文件,相当于达到了编译器中数据持久化的目的,注意该数据持久化,只会在编译模式下持久,发布运行时并不会保留数据;同时,如果多个对象关联了同一个数据文件,相当于他们服用了一组数据,更加节约内存

四、非持久数据

        1.非持久化数据指的是什么:不管是编辑器模式还是发布后都不会持久化的数据,我们可以根据需求随时创建对应数据对象进行使用,,如同直接new一个数据结构类对象一样

        2.如何利用ScriptableObject生成非持久化的数据:利用ScriptableObject中的静态方法CreateInstance<>(),该方法可以运行时创建出指定继承ScriptableObject的对象,且该对象只存在于内存当中,可以被GC,每调用一次便创建一次

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class Study4 : MonoBehaviour
  5. {
  6. public StudyUnity studyUnity;
  7. void Start()
  8. {
  9. //为了不想要数据持久化,不加载数据资源文件
  10. studyUnity = ScriptableObject.CreateInstance<StudyUnity>();
  11. studyUnity=ScriptableObject.CreateInstance("Studyunity") as StudyUnity;
  12. //创建出来的对象是一个基类对象,父类装子类,需要as
  13. //以上方式创建出来的对象,它的默认值不会受到脚本中设置的影响
  14. }
  15. //studyUnity = ScriptableObject.CreateInstance<StudyUnity>();
  16. //会发生报错
  17. }

        3.ScriptableObject非持久化数据存在的意义:

                如果希望在运行时能有一组唯一的数据可以使用,但是这个数据又不太希望保存为数据资源文件浪费空间,那么非持久化数据的好处便可以体现,其特点为:只是在运行时使用,在编辑器模式下也不会保存在本地(停止运行后,数据便会丢失)

五、如何让其拥有真正意义上的持久

        数据持久化本质上是读取硬盘上的内容到内存当中,需要的时候将内存当中的内容存储到硬盘上,游戏退出程序关闭后,数据信息就会被储存在硬盘上,达到持久化的目的

        持久化一般采用 PlayerPrefs/XML/Json/2进制的方式

        实际上ScriptableObject并不适合用来做数据持久化的功能,但我们可以利用学过的数据持久化方案令其持久化

        例如利用Json

                   存储数据:

  1. studyData.i=10086;
  2. studyData.f=8.8f;
  3. studyData.b=false;
  4. string str=JsonUtility.ToJson(studyData);
  5. File.WriteAllText(Application.persistentDataPath+"/test.json",str);
  6. //File需要引用命名空间

                   读取数据:

  1. string str =File.ReadAllText(Application.persistentDataPath+"/test.json");
  2. //反序列化数据文件

                   从本地读取Json字符串,根据json字符串反序列化出数据,将内容覆盖到数据对象之中

JsonUtility.FromJsonOverwrite(str,data);

             实际上,使用ScriptableObject来做持久化并非是好的选择,更有一种画蛇添足的意思

六、 使用ScriptableObject来配置数据

        为什么要使用ScriptableObject数据文件来作配置文件?

        配置文件的数据在游戏发布之前便已经定好了规则,配置数间的数据在游戏运行时只会读出来使用,并不会改变其内容。同时在untiy的Inspector窗口进行配置更加的方便(不需要使用第三方软件)

适用范围:只用不改,经常配置的数据,例如untiy内置的技能编译器,关卡编译器等(内置编译器只会在编译模式下进行,编译模式下ScriptableObject具备数据持久化的特性)

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. [CreateAssetMenu(fileName = "StudyInfo",menuName ="ScriptableObject/信息")]
  5. public class StudyInfo : ScriptableObject
  6. {
  7. //自定义类型想要可编辑,需要添加下行代码
  8. [System.Serializable]
  9. public class StudyData
  10. {
  11. public string Name;
  12. public string Description;
  13. }
  14. public List<StudyData> studyList;
  15. }

之后回到unity,在窗口创建后,我们可以看到

        

想获取以此法创建出来的数据,可以在一个脚本中创建一个对应对象,将脚本挂载到物体上进行关联,便可以获取到对应数据

七、使用ScriptableObject来复用数据

        使用预设体可能存在内存浪费,例如创建一个子弹,其速度是相同的,但是在实际上子弹速度在每次创建时都要占用一定内存(只用不变的数据)

        对于不同的对象,使用相同的数据,可以使用ScriptableObject节约内存(即使游戏被发布,也是使用一块内存空间)

八、数据带来的多态性为

        某些行为的变化是因为数据的不同带来的,我们可以利用面向对象的特性和原则,以及设计模式的知识点,结合ScriptableObject做出更方便的功能,比如随机音效(利用里氏替换和依赖倒转原则),物品拾取和AI等

例如

        

  1. public abstract class AudioPlayBase : ScriptableObject
  2. {
  3. public abstract void Play(AudioSource source);
  4. }

          

  1. [CreateAssetMenu()]
  2. public class RandomPlay : AudioPlayBase
  3. {
  4. public List<AudioClip> clips;
  5. //随机播放的音效文件
  6. public override void Play(AudioSource source)
  7. {
  8. if (clips.Count == 0) return;
  9. //设置音效切片文件
  10. source.clip = clips[Random.Range(0,clips.Count)];
  11. //进行播放
  12. source.Play();
  13. }
  14. }

九、单例模式化的数据获取

        对于只用不变并且要复用的数据,我们往往要在很多地方获取他们,如果我们直接在public关联或者动态加载。如果多处使用,会存在多处重复代码,开发效率较低。如果我们将此类数据通过但理论模式化的去获取,可以提升效率,减少代码量

        实现ScriptableObject数据单例模式基类:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class SingleScriptableObject<T>:ScriptableObject where T:ScriptableObject
  5. {
  6. private static T instance;
  7. //数据基类,不能直接去new
  8. public static T Instance {
  9. get {
  10. if(instance == null)
  11. {
  12. //如果为空,首先去资源路径下加载对应的数据资源文件
  13. instance=Resources.Load<T>("ScriptableObject/" + typeof(T).Name);
  14. //Load需要继承Object类,由于ScriptableObject已经继承过了
  15. //因此只需补充where T:ScriptableObject即可
  16. }
  17. //防止没有这个文件从而发生错误
  18. if(instance == null)
  19. {
  20. instance = CreateInstance<T>();
  21. }
  22. //甚至可以在这里 从json当中读取数据
  23. return instance;
  24. }
  25. }
  26. }

        

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/981321
推荐阅读
相关标签
  

闽ICP备14008679号