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

news2025/1/18 17:05:23

一、相关简介

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

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

二、ScriptableObject的创建

1.自定义ScriptableOject数据容器

        继承ScriptableObject类

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

public class StudyUnity : ScriptableObject
{
    //可以在其中声明任何一种类型的变量,
    //如果想要在Inspector窗口中能够编辑它,那么
    //声明变量的规则应该与MonoBehavior的public变量规则相同

    public bool a;
    public float b;

    public GameObject c;
    public Material d;
}

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

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

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

具体的方式有两种:

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

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


[CreateAssetMenu(fileName ="a文件",menuName ="b菜单",order =0)]

public class StudyUnity : ScriptableObject
{
    //可以在其中声明任何一种类型的变量,
    //如果想要在Inspector窗口中能够编辑它,那么
    //声明变量的规则应该与MonoBehavior的public变量规则相同

    public bool a;
    public float b;

    public GameObject c;
    public Material d;
}

这时我们回到unity可以看到

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

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

public class Study2
{
    [MenuItem("a/Tostudy")]
    //using UnityEditor;

    public static void ToStudy()
    {

    }
}

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

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

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

public class Study2
{
    [MenuItem("a/ToStudy")]
    //using UnityEditor;

    public static void ToStudy()
    {
        StudyUnity s=ScriptableObject.CreateInstance<StudyUnity>();

        //通过编译器API,可以根据数据创建一个数据资源文件
        AssetDatabase.CreateAsset(s, "Assets/Studt2data.asset");
        //在Assets路径下创建Studt2data.asset

        //保存创建的资源
        AssetDatabase.SaveAssets();

        //刷新界面
        AssetDatabase.Refresh();
    }
}

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,每调用一次便创建一次

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

public class Study4 : MonoBehaviour
{
    public StudyUnity studyUnity;

    void Start()
    {
        //为了不想要数据持久化,不加载数据资源文件
        studyUnity = ScriptableObject.CreateInstance<StudyUnity>();
        
        studyUnity=ScriptableObject.CreateInstance("Studyunity") as StudyUnity;
        //创建出来的对象是一个基类对象,父类装子类,需要as
    
        //以上方式创建出来的对象,它的默认值不会受到脚本中设置的影响
    }
    //studyUnity = ScriptableObject.CreateInstance<StudyUnity>();
    //会发生报错
        
     
}

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

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

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

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

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

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

        例如利用Json

                   存储数据:

studyData.i=10086;
studyData.f=8.8f;
studyData.b=false;

string str=JsonUtility.ToJson(studyData);

File.WriteAllText(Application.persistentDataPath+"/test.json",str);
//File需要引用命名空间

                   读取数据:

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

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

JsonUtility.FromJsonOverwrite(str,data);

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

六、 使用ScriptableObject来配置数据

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

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

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

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

[CreateAssetMenu(fileName = "StudyInfo",menuName ="ScriptableObject/信息")]
public class StudyInfo : ScriptableObject
{
    //自定义类型想要可编辑,需要添加下行代码
    [System.Serializable]
    public class StudyData
    {
        public string Name;
        public string Description;
            
    }

    
    public List<StudyData> studyList;
}

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

        

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

七、使用ScriptableObject来复用数据

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

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

八、数据带来的多态性为

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

例如

        

public  abstract class AudioPlayBase : ScriptableObject
{
    public abstract void Play(AudioSource source);

}

          

[CreateAssetMenu()]
public class RandomPlay : AudioPlayBase
{
    public List<AudioClip> clips;
    //随机播放的音效文件


    public override void Play(AudioSource source)
    {
        if (clips.Count == 0) return;


        //设置音效切片文件
        source.clip = clips[Random.Range(0,clips.Count)];
        //进行播放
        source.Play();
    
    }

    
}

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

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

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

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

public class SingleScriptableObject<T>:ScriptableObject where T:ScriptableObject
{
    private static T instance;

    //数据基类,不能直接去new
    public static T Instance {

        get { 

            if(instance == null)
            {
                //如果为空,首先去资源路径下加载对应的数据资源文件
                instance=Resources.Load<T>("ScriptableObject/" + typeof(T).Name);
                //Load需要继承Object类,由于ScriptableObject已经继承过了
                //因此只需补充where T:ScriptableObject即可
            }

            //防止没有这个文件从而发生错误
            if(instance == null)
            {
                instance = CreateInstance<T>();
            }
            //甚至可以在这里 从json当中读取数据

            return instance;
        }

    }
    
}

        

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

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

相关文章

[BeginCTF]真龙之力

安装程序 双击安装 出现了安装失败的标签&#xff0c;开发者不允许测试。 查看Mainfest入口文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android" android:versionCo…

Blender_pmx导出fbx

Blender_pmx导出fbx 学无止境&#xff1f; 相关链接&#xff1a; Blender教程&#xff1a; Blender中文手册介绍 — Blender Manualhttps://docs.blender.org/manual/zh-hans/2.79/about/introduction.htmlhttps://www.blendercn.org/https://www.blendercn.org/Blender下载…

dddddddddddddddddddd

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

深度学习(13)--PyTorch搭建神经网络进行气温预测

一.搭建神经网络进行气温预测流程详解 1.1.导入所需的工具包 import numpy as np # 矩阵计算 import pandas as pd # 数据读取 import matplotlib.pyplot as plt # 画图处理 import torch # 构建神经网络 import torch.optim as optim # 设置优化器 1.2.读取并处理数据…

PWM输入输出

PWM&#xff08;Pulse Width Modulation&#xff09;即脉冲宽度调制&#xff0c;在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行制&#xff0c;来等效地获得所需要的模拟参量&#xff0c;常应用于电机控速、开关电源等领域。 PWM参数 PWM 中有三个重要参数&…

代码随想录算法训练营第四十七天(动态规划篇)| 416. 分割等和子集

416. 分割等和子集 题目链接&#xff1a;416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; 思路 回溯——超时 首先想到之前的回溯算法&#xff0c;寻找数组中加和等于sum(nums)/2的子集&#xff0c;但对于大数组超时了&#xff1a; class Solution(object):def…

nodejs+vue高校实验室耗材管理系统_m20vy

用户功能&#xff1a; 登录后要有一个首页 比如:可以看见目前的耗材消耗记录&#xff0c;可做成图表菜单栏在左侧显示 1.个人信息管理 可以对基本信息进行修改&#xff0c;(修改密码时需要验证) 2.耗材管理&#xff08;耗材信息&#xff09; 普通用户可以查询当前相关耗材信息[…

[Java][算法 哈希]Day 01---LeetCode 热题 100---01~03

LeetCode 热题 100---01~03 ------->哈希 第一题 两数之和 思路 最直接的理解就是 找出两个数的和等于目标数 这两个数可以相同 但是不能是同一个数字&#xff08;从数组上理解就是内存上不是同一位置&#xff09; 解法一&#xff1a;暴力法 暴力解万物 按照需求 …

C++类型转化cast from pointer to smaller type ‘int‘ loses information

代码如下 #include <iostream>int main() {int a 10;std::cout << (int)&a << std::endl;return 0; }编译 这段代码是要将地址转化成整数类型&#xff0c;但是在编译时编译器告诉我们这是错的&#xff0c;因为在C中&#xff0c;将指针转换为int类型的…

Codeforces Edu 74 E. Keyboard Purchase 【状压DP +贡献】

E. Keyboard Purchase 题意 给定一个长度为 n n n 的字符串 s s s 仅由前 m m m 个小写字母组成 现在要求求出包含前 m m m 个小写字母的键盘&#xff0c;使得在键盘上敲出 s s s 要移动的距离最短 移动总距离为&#xff1a; ∑ i 2 n ∣ p o s s i − 1 − p o s s i…

LabVIEW热电偶自动校准系统

设计并实现一套基于LabVIEW平台的工业热电偶自动校准系统&#xff0c;通过自动化技术提高校准效率和精度&#xff0c;降低人力成本&#xff0c;确保温度测量的准确性和可靠性。 工业生产过程中&#xff0c;温度的准确测量对产品质量控制至关重要。传统的热电偶校准方式依赖人工…

昆仑万维发布天工 2.0 大语言模型及AI助手App;AI成功破解2000年前碳化古卷轴

&#x1f989; AI新闻 &#x1f680; 昆仑万维发布天工 2.0 大语言模型及AI助手App 摘要&#xff1a;昆仑万维近日推出了新版MoE大语言模型“天工 2.0”和相应的“天工 AI 智能助手”App&#xff0c;宣称为国内首个面向C端用户免费的基于MoE架构的千亿级参数大模型应用。天工…

MacOS上怎么把格式化成APFS的U盘或者硬盘格式化回ExFAT?

一、问题 MacOS在更新MacOS Monterey后或者更高系统后发现&#xff0c;格式U盘或者硬盘只有4个APFS选项&#xff0c;那么我们该如何将APFS格式成ExFAT&#xff1f; 二、解答 将APFS的U盘或者硬盘拓展成MacOS的拓展格式即可&#xff0c;操作步骤如下 1、电脑接入U盘或者硬盘 2…

从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&#xff1a;[3…

C++ PE文件信息解析

尝试解析PE文件结构, 于是编写了此PE信息助手类, 暂时完成如下信息解析 1.导出表信息(Dll模块, 函数) 2.导入表信息(Dll模块, 函数) 3.资源表信息(字符串表, 版本信息, 清单信息) CPEHelper.h #pragma once// // brief: PE文件解析助手类 // copyright: Copyright 2024 Flame…

MySQL数据库⑦_复合查询+内外链接(多表/子查询)

目录 1. 回顾基本查询 2. 多表查询 2.1 笛卡尔积初步过滤 3. 自连接 4. 子查询 4.1 单行子查询 4.2 多行子查询 4.2 多列子查询 4.2 from子句中使用子查询 5. 合并查询 6. 内外链接 6.1 内连接 6.2 左外链接 6.2 右外连接 本篇完。 1. 回顾基本查询 先回顾一下…

51单片机编程应用(C语言):串口通信

目录 通信的基本概念和种类 1.1串行通信与并行通信 ​编辑 1.2同步通信与异步通信 1.3单工&#xff0c;半双工&#xff0c;全双工 1.4通信速率 二、波特率和比特率的关系 串口通信简介&#xff1a; 1.接口标准 RS-232 2、D型9针接口定义 3.通信协议&#xff1a; …

OCP使用web console创建和构建应用

文章目录 环境登录创建project赋予查看权限部署第一个image检查pod扩展应用 部署一个Python应用连接数据库创建secret加载数据并显示国家公园地图 清理参考 环境 RHEL 9.3Red Hat OpenShift Local 2.32 登录 在 crc start 启动crc时&#xff0c;可以看到&#xff1a; .....…

2 月 7 日算法练习- 数据结构-树状数组上二分

问题引入 给出三种操作&#xff0c; 0在容器中插入一个数。 1在容器中删除一个数。 2求出容器中大于a的第k大元素。 树状数组的特点就是对点更新&#xff0c;成段求和&#xff0c;而且常数非常小。原始的树状数组只有两种操作&#xff0c;在某点插入一个数和求1到i的所有数的…

C++,stl,栈stack和队列queue详解

1.栈stack 1.stack基本概念 2.stack常用接口 代码示例&#xff1a; #include<bits/stdc.h> using namespace std;int main() {stack<int> stk;stk.push(7);stk.push(9);stk.push(5);cout << "栈的size为&#xff1a;" << stk.size() <…