Unity进阶之ScriptableObject

news2025/1/14 1:07:16

目录

  • ScriptableObject 概述
  • ScriptableObject数据文件的创建
  • 数据文件的使用
  • 非持久数据
  • 让其真正意义上的持久
  • ScriptableObject的应用
    • 配置数据
    • 复用数据
    • 数据带来的多态行为
    • 单例模式化的获取数据

ScriptableObject 概述

ScriptableObject是什么
ScriptableObject是Unity提供的一个数据配置存储基类
它是一个可以用来保存大量数据的数据容器
就像是可以自定义的数据资源文件
它是一个类似MonoBehavior的基类
需要我们继承它来进行使用
它的主要作用是
1.数据复用(多个对象用同一个数据)
2.配置文件(配置游戏中的数据)
3.编辑模式下的数据持久化
数据复用
比如一个子弹对象
以前我们通过面向对象的思想去做的话
会写一个继承MonoBehaviour的脚本
相关的属性都会在这里声明
然后挂载到子弹模型预设体上
这样每次实例化一个子弹,如果数据不变
那么对内存来说,是有一定浪费的
因为每一个子弹预设体上都有该脚本
那么所有的属性都会分配一次内存
通过使用ScriptableObject可以有效避免内存的浪费
配置文件
以前我们要通过配置文件配置游戏相关的数据,比如玩家数据、怪物数据等等
是通过数据持久化相关知识来完成的,我们一般会通过xml、json、excel等方式来配置游戏数据
相对来说都是在Unity外部通过其它格式的文件对数据进行配置
而通过ScriptableObject我们可以直接在Unity内部
在Inspector窗口中就可以进行数据的配置
编辑模式下的数据持久化
当我们在编辑模式下修改了继承ScriptableObject对象的数据文件内容时
这些修改将被记录下来
因此在编辑模式下ScriptableObject是具有数据持久化特性的

但是需要注意的是,在发布运行时
ScriptableObject并不具备持久化特性(修改数据对象,并不会保存在本地)
ScriptableObject的好处
1.我们可以直接在Inspector窗口编辑配置数据,可以利用它来做配置文件
2.处理重复数据,减少数据拷贝时造成的内存占用,可以利用它来做公共数据
3.可以更方便的处理数据带来的多态行为

ScriptableObject数据文件的创建

自定义ScriptableObject数据容器
1.继承ScriptableObject类
2.在该类中声明成员(变量、方法等)

注意:声明后,我们边可以在Inspector窗口中看到变化
我们可以在其中进行设置,但是这些设置都是默认数据,并没有真正使用他们
这些关联信息都是通过脚本文件对应的Unity配置文件meta进行记录的
目前该数据只是一个数据容器模板
有了它我们之后才能根据它的信息创建对应的数据资源文件

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

具体的方法有两种:
//1.为类添加CreateAssetMenu通过菜单创建资源特性
[CreateAssetMenu(fileName = “默认文件名”, menuName = “在Asset/Create菜单中显示的名字”, order = 再Asset/Create菜单中的位置(多个时可以通过它来调整顺序))]

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

public class ScriptableObjectTool
{
    [MenuItem("ScriptableObject/CreateMyData")]
    public static void CreateMyData()
    {
        //书写创建数据资源文件的代码
        MyData asset = ScriptableObject.CreateInstance<MyData>();

        //通过编辑器API 根据数据创建一个数据资源文件
        AssetDatabase.CreateAsset(asset, "Assets/Resources/MyDataTest.asset");
        //保存创建的资源
        AssetDatabase.SaveAssets();
        //刷新界面
        AssetDatabase.Refresh();
    }
}

ScriptableObject好处的体现
1.更方便的配置数据,我们可以直接在Inspector当中配置数据
2.项目之间的复用,我们可以拷贝继承ScriptableObject的脚本到任何工程中

数据文件的使用

ScriptableObject数据文件的使用
1.通过Inspector中的public变量进行关联
1-1.创建一个数据文件
1-2.在继承MonoBehaviour类中申明数据容器类型的成员
在Inspector窗口进行关联

2.通过资源加载的信息关联
加载数据文件资源
注意:Resources、AB包、Addressables都支持加载继承ScriptableObject的数据文件

data = Resources.Load<MyData>("MyDataTest");
data.PrintInfo();

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

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

Awake 数据文件创建时调用

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

OnValidate 编辑器才会调用的函数,Unity在加载脚本或者Inspector窗口中更改值时调用
ScriptableObject好处的体现
1.编辑器中的数据持久化
通过代码修改数据对象中内容,会影响数据文件
相当于达到了编辑器中数据持久化的目的
(该数据持久化 只是在编辑模式下的持久,发布运行时并不会保存数据)
2.复用数据
如果多个对象关联同一个数据文件
相当于他们复用了一组数据,内存上更加节约空间

非持久数据

ScriptableObject的非持久化数据指的是什么
指的是不管在编辑器模式还是在发布后都 不会持久化的数据
我们可以根据自己的需求随时创建对应数据对象进行使用
就好像直接new一个数据结构类对象
如何利用ScriptableObject生成非持久化的数据
利用ScriptableObject中的静态方法 CreateInstance<>()
该方法可以在运行时创建出指定继承ScriptableObject的对象
该对象只存在于内存当中,可以被GC
调用一次就创建一次

通过这种方式创建出来的数据对象 它里面的默认值 不会受到脚本中设置的影响
ScriptableObject的非持久化数据存在的意义
只是希望在运行时能有一组唯一的数据可以使用
但是这个数据又不太希望保存为数据资源文件浪费硬盘空间
那么ScriptableObject的非持久化数据就有了存在的意义
它的特点是
只在运行时使用,在编辑器模式下也不会保存在本地

让其真正意义上的持久

利用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);

利用Json结合ScriptableObject读取数据

//从本地读取 Json字符串
string str = File.ReadAllText(Application.persistentDataPath + "/testJson.json");
//根据json字符串反序列化出数据 将内容覆盖到数据对象中
JsonUtility.FromJsonOverwrite(str, data);
data.PrintInfo();

ScriptableObject的应用

配置数据

ScriptableObject数据文件为什么非常适合用来做配置文件?
1.配置文件的数据在游戏发布之前定规则
2.配置文件的数据在游戏运行时只会读出来使用,不会改变内容
3.在Unity的Inspector窗口进行配置更加的方便
举例制作
以前我们的常规配置方式
都是利用之前学习过的 数据持久化四部曲当中的内容进行配置的
比如 xml配置 json配 置 excel配置
1、创建RoleInfo.cs脚本

[CreateAssetMenu(fileName ="RoleInfo", menuName = "ScriptableObject/角色信息")]
public class RoleInfo : ScriptableObject
{
    [System.Serializable]
    public class RoleData
    {
        public int id;
        public string res;
        public int atk;
        public string tips;
        public int lockMoney;
        public int type;
        public string hitEff;

        public void Print()
        {
            Debug.Log(id);
            Debug.Log(res);
            Debug.Log(atk);
            Debug.Log(tips);
            Debug.Log(lockMoney);
            Debug.Log(type);
            Debug.Log(hitEff);
        }
    }

    public List<RoleData> roleList;
}

2、使用数据

public RoleInfo info;
for (int i = 0; i < info.roleList.Count; i++)
{
    info.roleList[i].Print();
}

我们可以利用ScriptableObject数据文件 来制作编辑器相关功能
比如:Unity内置的技能编辑器、关卡编辑器等等
我们不需要把编辑器生成的数据生成别的数据文件,而是直接通过ScriptableObject进行存储
因为内置编辑器只会在编辑模式下运行,编辑模式下ScriptableObject具备数据持久化的特性

复用数据

使用预设体对象可能存在的内存浪费问题
对于只用不变的数据
以面向对象的思想去声明对象类是可能存在内存浪费的问题的
举例说明 利用ScriptableObject数据对象 更加节约内存
1、创建BulletInfo.cs脚本

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

2、创建Bullet脚本

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);
    }
}

数据带来的多态行为

某些行为的变化是因为数据的不同带来的
我们可以利用面向对象的特性和原则,以及设计模式相关知识点
结合ScriptableObject做出更加方便的功能

比如随机音效,物品拾取,AI等等等
随机音效(里氏替换原则和依赖倒转原则)
播放音乐时,可能会随机播放多个音效当中的一种

物品拾取(里氏替换原则和依赖倒转原则)
比如拾取一个物品,物品给玩家带来不同的效果

AI
不同数据带来的不同行为模式

为了方便我们使用,我们可以利用ScriptableObject的可配置性来制作这些功能
举例讲解

单例模式化的获取数据

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

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

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;
        }
    }
}

2、使用:将RoleInfo继承该类
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1618170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue+OpenLayers7入门到实战,OpenLayers加载GeoJson数据并叠加GeoJson中的要素到地图上

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7入门到实战 前言 本章介绍如何使用OpenLayers7在地图上加载GeoJson数据并叠加GeoJson中的要素到OpenLayers矢量图层上。 GeoJson数据格式可以参考博主另一篇文章《GIS开发入门,GeoJSON是什么?GeoJSON格式标准介绍》,那么…

Python Selenium无法打开Chrome浏览器处理自定义浏览器路径

问题 在使用Python Selenium控制Chrome浏览器操作的过程中&#xff0c;由于安装的Chrome浏览器的版本找不到对应版本的驱动chromedriver.exe文件&#xff0c;下载了小几个版本号的驱动软件。发现运行下面的代码是无法正常使用的&#xff1a; from selenium import webdriver …

在excel中,如何在一个表中删除和另一个表中相同的数据?

现在有A表&#xff0c;是活动全部人员的姓名和学号&#xff0c;B表是该活动中获得优秀人员的姓名和学号&#xff0c; 怎么提取没有获得优秀人员的名单&#xff1f; 这里提供两个使用excel基础功能的操作方法。 1.条件格式自动筛选 1.1按住Ctrl键&#xff0c;选中全表中的姓…

电机控制专题(一)——最大转矩电流比MTPA控制

文章目录 电机控制专题(一)——最大转矩电流比MTPA控制前言理论推导仿真验证轻载1Nm重载30Nm 总结 电机控制专题(一)——最大转矩电流比MTPA控制 前言 MTPA全称为Max Torque Per Ampere&#xff0c;从字面意思就可以知道MTPA算法的目的是一个寻优最值问题&#xff0c;可以从以…

如何高效的压缩GIF图片?一键搞定GIF动图压缩 就是这么简单

一&#xff0c;引言 压缩GIF动图是一个常见的需求&#xff0c;无论是在社交媒体上分享动态表情&#xff0c;还是在网页设计中添加动态元素&#xff0c;GIF动图都扮演着重要的角色。然而&#xff0c;过大的GIF文件大小可能会导致加载速度慢&#xff0c;影响用户体验。因此&…

【每日刷题】Day22

【每日刷题】Day22 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1669. 合并两个链表 - 力扣&#xff08;LeetCode&#xff09; 2. 11. 盛最多水的容器 - 力扣&#…

茶饮门店本地生活抖音团购运营方案计划书

【干货资料持续更新&#xff0c;以防走丢】 茶饮门店本地生活抖音团购运营方案计划书 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑80页&#xff08;完整资料包含以下内容&#xff09; 目录 抖音本地生活运营方案 1. 账号基础搭建与优化 - 门店账号…

MTK6775/MT6775/曦力P70联发科处理器性能参数资料

联发科MT6775(曦力P70)芯片搭载强大的Arm Cortex-A73/A53八核CPU&#xff0c;并采用台积电12纳米FinFET制程工艺&#xff0c;相较于其他14纳米级别产品&#xff0c;功耗节省达到了15%。此外&#xff0c;曦力P70还配备了高效能的Arm Mali-G72 GPU&#xff0c;相比上一代产品曦力…

sklearn 笔记 metrics

1 分类 1.1 accuracy_score 分类准确率得分 在多标签分类中&#xff0c;此函数计算子集准确率&#xff1a;y_pred的标签集必须与 y_true 中的相应标签集完全匹配。 1.1.1 参数 y_true真实&#xff08;正确&#xff09;标签y_pred由分类器返回的预测标签normalize 默认为 Tr…

简单的图像处理算法

基础&#xff1a;图像处理都是用卷积矩阵对图像卷积计算&#xff0c;如3X3 的矩阵对640 X 480分辨率的图像卷积&#xff0c;最终会得到638 X 478 的图像。卷积过程是这样的&#xff1a; 一、中值滤波 &#xff1a; 找出矩阵中的最中间值作为像素点 二、均值滤波&#xff1a;找…

洛基计划project loki加速器推荐 免费低延迟联机加速器分享

洛基计划project loki加速器推荐 免费低延迟联机加速器分享 《洛基计划》是一款团队PVP游戏&#xff0c;融合有动作、英雄设计、大逃杀等元素&#xff0c;由前拳头游戏、Bungie和暴雪娱乐员工创立的新工作室Theorycraft Games共同发布。《洛基计划》汇集了一些大型团队PVP游戏…

(ICML-2021)从自然语言监督中学习可迁移的视觉模型

从自然语言监督中学习可迁移的视觉模型 Title&#xff1a;Learning Transferable Visual Models From Natural Language Supervision paper是OpenAI发表在ICML 21的工作 paper链接 Abstract SOTA计算机视觉系统经过训练可以预测一组固定的预定目标类别。这种受限的监督形式限制…

齐次变换矩阵、欧拉角

目录 齐次变换矩阵旋转矩阵如何计算平移矩阵如何计算实例 欧拉角和齐次变换矩阵互相转换 齐次变换矩阵 因为老是忘记齐次变换矩阵的含义以及方向&#xff0c;每次推导公式都很费劲&#xff0c;写下这篇文章用于快速回顾齐次变换矩阵。 表示的是&#xff1a;坐标系A到坐标系B的…

电脑问题快速判断

电脑开机没有任何反应 检查电源 检查电源是否有问题或损坏&#xff0c;可以短接方法检测 板电源卡口对自己接第四或第五根线&#xff0c;若风扇匀速转动&#xff0c;电源无问题&#xff0c;若不转动或转一下停一下&#xff0c;电源有问题 检查内部连线 确保主板上的线插的…

【C语言】手撕二叉树

标题&#xff1a;【C语言】手撕二叉树 水墨不写bug 正文开始&#xff1a; 二叉树是一种基本的树形数据结构&#xff0c;对于初学者学习树形结构而言较容易接受。二叉树作为一种数据结构&#xff0c;在单纯存储数据方面没有 顺序表&#xff0c;链表&#xff0c;队列等线性结构…

软件项目经理需要具备这 11 个能力

当前软件开发技术更新换代越来越快&#xff0c;各种项目实施管理思想也日新月异&#xff0c;作为一个软件项目经理&#xff0c;需要具备这 11 种能力&#xff1a; 1. 项目管理能力 了解项目管理的基本原则和方法&#xff0c;包括制定项目计划、资源分配、风险管理、问题解决和…

婚恋相亲红娘牵线系统源码支持微信小程序+微信公众号+H5+APP社交交友系统搭建,扩展你的社交影响力与人脉资源

当代年轻人晚婚晚育甚至不愿意结婚不愿意相亲等问题愈来愈严重了&#xff0c;但是如果抛开表现去追求本质的话&#xff0c;其实不难发现年轻人们还是会喜欢去找一些志同道合或者聊得来的异性朋友交流&#xff0c;从线上发展到线下的一个流程。 核心系统核心体系是恋爱小贴士、…

概率图模型在机器学习中的应用:贝叶斯网络与马尔可夫随机场

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

嵌入式s5p5818核心板介绍

底板寻址空间介绍 s5p6818 寻址空间采用统一编址方式进行管理 寻址空间映射图&#xff1a; 独立寻址&#xff1a;片内片外存储器只能选择其中一个 统一寻址&#xff1a;片内片外存储器都能使用&#xff0c;且使用的是同一片连续的寻址空间 reserved保留&#xff0c;Normaol …

【代码】Python3|用Python PIL压缩图片至指定大小,并且不自动旋转

代码主体是GPT帮我写的&#xff0c;我觉得这个功能非常实用。 解决自动旋转问题参考&#xff1a;一行代码解决PIL/OpenCV读取图片出现自动旋转的问题&#xff0c;增加一行代码image ImageOps.exif_transpose(image) 即可恢复正常角度。 from PIL import Image, ImageOpsdef …