jjzjj

unity-ScriptableObject的详细讲解

神奇的阿邓 2024-06-23 原文

ScriptableObject是什么

是Unity提供的一个数据配置存储的基类。可以用来保存大量数据的数据容器,
是一个可以自定义数据的资源文件,一般用来当关卡配置,或者其他的配置一类的文件,一般用于只用不改的公共数据。
可以发现,这个能做的和单例类也能做,单例类也是共享一份数据,有什么区别?
首先,当我们在编辑模式下修改了继承自 ScriptableObject 对象的数据文件内容时,修改的数据将被保存到磁盘上。但是在发布运行后,即使在游戏中修改了 ScriptableObject 的数据,改后的数据并不会保存在本地,重新打开运行时数据并还是配置的初始数据。

主要作用

  • 1、 数据复用(多个对象用同一个数据,节省性能,避免了每个类都去申请空间,浪费)
  • 2、配置文件(配置游戏中的数据)
  • 3、编辑模式下的数据持久化

数据复用




创建的方法

1、

这种比较简便,在project文件内,点击加号就能看到,这种方法需要继承ScripteableObject类

2、

在顶部菜单栏创建,自主传入类名,指定生成位置

使用方法

1、直接声明一个资源类,然后在inspector,直接将asset拖上去
2、放到能加载到的文件夹内,直接加载
3、通过单例模式去加载,这样不用去动态加载和手动拖取
3、数据只会在编辑模式才会被更改,也可以在编辑模式下,运行时候用代码更改,但是不能再打包出去后更改

    void Start()
    {
        #region 知识点一 ScriptableObject数据文件的使用
        //1.通过Inspector中的public变量进行关联
        //1-1.创建一个数据文件
        //1-2.在继承MonoBehaviour类中申明数据容器类型的成员
        //    在Inspector窗口进行关联
        //data.PrintInfo();

        //2.通过资源加载的信息关联
        //加载数据文件资源
        //注意:Resources、AB包、Addressables都支持加载继承ScriptableObject的数据文件
        data = Resources.Load<MyData>("MyDataTest");
        data.PrintInfo();

        //注意:如果多个对象关联同一个数据容器文件,他们共享的是一个对象
        //     因为是引用对象,所以在其中任何地方修改后,其它地方也会发生改变
        #endregion

        #region 知识点二 ScriptableObject的生命周期函数
        //ScriptableObject和MonoBehavior很类似
        //它也存在生命周期函数
        //但是生命周期函数的数量更少
        //主要做了解,一般我们使用较少

        //Awake 数据文件创建时调用

        //OnDestroy ScriptableObject 对象将被销毁时调用
        //OnDisable ScriptableObject 对象销毁时、即将重新加载脚本程序集时 调用
        //OnEnable ScriptableObject 创建或者加载对象时调用

        //OnValidate 编辑器才会调用的函数,Unity在加载脚本或者Inspector窗口中更改值时调用
        #endregion

        #region 知识点三 ScriptableObject好处的体现
        //1.编辑器中的数据持久化
        //通过代码修改数据对象中内容,会影响数据文件
        //相当于达到了编辑器中数据持久化的目的
        //(该数据持久化 只是在编辑模式下的持久,发布运行时并不会保存数据)
        data.i = 9999;
        data.f = 5.5f;
        data.b = false;

        //2.复用数据
        //如果多个对象关联同一个数据文件
        //相当于他们复用了一组数据,内存上更加节约空间
        #endregion

        #region 总结
        //其实创建出来的数据资源文件,你可以把它理解成一种记录数据的资源
        //它的使用方式,和我们以前使用Unity当中的其它资源规则是一样的
        //比如:预设体、音频文件、视频文件、动画控制器文件、材质球等等
        //只不过通过继承ScriptableObject类生成的数据资源文件,它主要是和数据相关的
        #endregion
    }

非持久化数据

 public MyData data;
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 ScriptableObject的非持久化数据指的是什么
        //指的是不管在编辑器模式还是在发布后都 不会持久化的数据
        //我们可以根据自己的需求随时创建对应数据对象进行使用
        //就好像直接new一个数据结构类对象
        #endregion

        #region 知识点二 如何利用ScriptableObject生成非持久化的数据
        //利用ScriptableObject中的静态方法 CreateInstance<>()
        //该方法可以在运行时创建出指定继承ScriptableObject的对象
        //该对象只存在于内存当中,可以被GC
        //调用一次就创建一次

        //通过这种方式创建出来的数据对象 它里面的默认值 不会受到脚本中设置的影响
        //data = ScriptableObject.CreateInstance("MyData") as MyData;
        data = ScriptableObject.CreateInstance<MyData>();

        data.PrintInfo();
        #endregion

        #region 知识点三 ScriptableObject的非持久化数据存在的意义
        //只是希望在运行时能有一组唯一的数据可以使用
        //但是这个数据又不太希望保存为数据资源文件浪费硬盘空间
        //那么ScriptableObject的非持久化数据就有了存在的意义
        //它的特点是
        //只在运行时使用,在编辑器模式下也不会保存在本地
        #endregion
    }

非持久化数据变成持久化

原理就是将类保存到其他持久化方式中,类如json xml、playerprefs、2进制等等,其实无意义,

 void Start()
    {
        #region 知识点一 回顾通过ScriptableObject创建非持久化数据
        MyData data = ScriptableObject.CreateInstance<MyData>();
        #endregion

        #region 知识点二 回顾数据持久化
        //硬盘<=>内存
        //使用数据时从硬盘中读取
        //数据改变后保存到硬盘上
        //游戏退出程序关闭后,数据信息会被存储到硬盘上,达到持久化的目的

        //我们讲授过的数据持久化相关知识
        //PlayerPrefs
        //XML
        //Json
        //2进制

        //ScriptableObject并不适合用来做数据持久化功能
        //但是我们可以利用我们学过的数据持久化方案 让其持久化
        #endregion

        #region 知识点三 利用Json结合ScriptableObject存储数据
        data.PrintInfo();

        //data.i = 9999;
        //data.f = 6.6f;
        //data.b = true;
        //将数据对象 序列化为 json字符串
        //string str = JsonUtility.ToJson(data);
        //print(str);
        把数据序列化后的结果 存入指定路径当中
        //File.WriteAllText(Application.persistentDataPath + "/testJson.json", str);
        //print(Application.persistentDataPath);
        #endregion

        #region 知识点四 利用Json结合ScriptableObject读取数据
        //从本地读取 Json字符串
        string str = File.ReadAllText(Application.persistentDataPath + "/testJson.json");
        //根据json字符串反序列化出数据 将内容覆盖到数据对象中
        JsonUtility.FromJsonOverwrite(str, data);
        data.PrintInfo();
        #endregion

        #region 总结
        //对于ScriptableObject的数据
        //由于它在游戏发布运行过程中无法被持久化
        //我们可以利用 PlayerPrefs、XML、Json、2进制等等方式
        //让其可以达到被真正持久化的目的

        //但是我个人并不建议大家利用ScriptableObject来做数据持久化
        //有点画蛇添足的意思了
        #endregion
    }

复用数据

例如 发射子弹,每个子弹上都有速度、攻击力等等(不变的,固定的),那么创建n个子弹就要开辟n份数据,这有点浪费。这样可以用通用的,然后只去改通用的,这些子弹就会都变化了。要是用单例去做,还要哪边都要去通过GetInstance去访问单例的对象,然后去写代码去更改,这里直接去更改数据更方便

public class Bullet : MonoBehaviour
{
    public BulletInfo info;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(Vector3.forward * info.speed * Time.deltaTime);
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu()]
public class BulletInfo : ScriptableObject
{
    public float speed;
    public int atk;
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson6 : MonoBehaviour
{
    public BulletInfo info;
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 使用预设体对象可能存在的内存浪费问题
        //对于只用不变的数据
        //以面向对象的思想去声明对象类是可能存在内存浪费的问题的

        //我们以子弹对象为例
        #endregion

        #region 知识点二 举例说明 利用ScriptableObject数据对象 更加节约内存

        #endregion

        #region 总结
        //对于不同对象,使用相同数据时
        //我们可以使用ScriptableObject来节约内存
        #endregion
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
            info.speed += 1;
    }
}

单例模式的应用

用单例模式可以避免很多代码,例如,以前要手动拖取或者动态加载,浪费事,

//继承自这个类的子类,去创建子类的ScriptableObject 
public class SingleScriptableObject<T> :ScriptableObject where T:ScriptableObject
{
    private static T instance;

    public static T Instance
    {
        get
        {
            //如果为空 首先应该去资源路劲下加载 对应的 数据资源文件
            if (instance == null)
            {
                //我们定两个规则
                //1.所有的 数据资源文件都放在 Resources文件夹下的ScriptableObject中
                //2.需要复用的 唯一的数据资源文件名 我们定一个规则:和类名是一样的
                instance = Resources.Load<T>("ScriptableObject/" + typeof(T).Name);
            }
            //如果没有这个文件 为了安全起见 我们可以在这直接创建一个数据
            if(instance==null)
            {
                instance = CreateInstance<T>();
            }
            //甚至可以在这里 从json当中读取数据,但是我不建议用ScriptableObject来做数据持久化

            return instance;
        }
    }
}
//这个TestData,去创建出一个名为TestData的asset,然后可以直接在其他类里点出来TestData.GetInstance().i
[CreateAssetMenu]
public class TestData : SingleScriptableObject<TestData>
{
    public int i;
    public bool b;
}

void Start()
    {
        #region 知识点一 为什么要单例模式化的获取数据
        //对于只用不变并且要复用的数据
        //比如配置文件中的数据
        //我们往往需要在很多地方获取他们
        //如果我们直接通过在脚本中 public关联 或者 动态加载
        //如果在多处使用,会存在很多重复代码,效率较低
        //如果我们将此类数据通过单例模式化的去获取
        //可以提升效率,减少代码量
        #endregion

        #region 知识点二 实现单例模式化获取数据
        //知识点
        //面向对象、单例模式、泛型等等

        //我们可以实现一个ScriptableObject数据单例模式基类
        //让我们只需要让子类继承该基类
        //就可以直接获取到数据
        //而不再需要去通过 public关联 和 资源动态加载

        print(RoleInfo.Instance.roleList[0].id);
        print(RoleInfo.Instance.roleList[1].tips);

        print(TestData.Instance.i);
        print(TestData.Instance.b);
        #endregion

        #region 总结
        //这种基类比较适合 配置数据 的管理和获取
        //当我们的数据是 只用不变,并且是唯一的时候,可以使用该方式提高我们的开发效率
        //在此基础上你也可以根据自己的需求进行变形
        //比如添加数据持久化的功能,将数据从json中读取,并提供保存数据的方法
        //但是不建议大家用ScriptableObject来制作数据持久化功能
        //除非你有这方面的特殊需求
        #endregion
    }

    // Update is called once per frame
    void Update()
    {
        
    }

参考:

https://blog.csdn.net/qq_46044366/article/details/124310241

有关unity-ScriptableObject的详细讲解的更多相关文章

  1. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  2. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  3. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  4. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

  5. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  6. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  7. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. 三分钟集成 TapTap 防沉迷 SDK(Unity 版) - 2

    三分钟集成Tap防沉迷SDK(Unity版)一、SDK介绍基于国家对上线所有游戏必须增加防沉迷功能的政策下,TapTap推出防沉迷SDK,供游戏开发者进行接入;允许未成年用户在周五、六、日以及法定节假日晚上8:00-9:00进行游戏,防沉谜时间段进入游戏会弹窗进行提示!开发环境要求:Unity2019.4或更高版本iOS10或更高版本Android5.0(APIlevel21)或更高版本🔗Unity集成Demo参考链接🔗UnityTapSDK功能体验APK下载链接二、集成前准备1.创建应用进入开发者后台,按照提示开始创建应用;2.开通服务在使用TDS实名认证和防沉迷服务之前,需要在上面创建的应

  10. 【Unity大气散射】GAMES104:3A中如何实现大气散射 - 2

    写在前面前两天学习并整理的大气散射基础知识:【Unity大气渲染】关于单次大气散射的理论知识,收获了很多,但不得不承认的是,这其实已经是最早的、90年代的非常古老的方法了,后来也出现了一些优化性的计算思路和方法。因此,我打算先不急着跟各种教程在Unity中实现大气散射,而是再花时间来看看最近的游戏是如何去实现大气渲染的:06.游戏中地形大气和云的渲染(下)|GAMES104-现代游戏引擎:从入门到实践接下来就跟着GAMES104讲地形大气和云渲染的部分学习并做简单的记录,涉及到之前没提到的Mie散射也只选择直接截图PPT的方式记录啦!毕竟对于做作品来说,之后实现出来才是重要的~当然,May佬的

随机推荐