前言
ScriptableObject
是一个可独立于类实例来保存大量数据的数据容器。它的一个主要用例是通过避免重复值来减少项目的内存使用量。
ScriptableObject
派生自基本 Unity 对象,但与 MonoBehaviour 不同,不能将它附加到游戏对象。正确的做法是需要将它们保存为项目中的资源。
简而言之,ScriptableObject
是一种Unity
提供可自定义的一种数据结构,使用ScriptableObject
创建出的文件通常保留在项目中,成为一种本地数据
。
使用情景
一、游戏存档
如上所言,作为本地的数据,是可以通过最初的结构设计上使其能够进行修改和创建的,以下为实现的一个简单演示案例。
1.创建ScriptableObject子类
这里我创建了一个名为ArchiveSO
的类对象用于继承ScriptableObject
using System.Collections.Generic;
using UnityEngine;
// 声明使用CreateAssetMenu,之后我们会在右键创建菜单栏里实例出ArchiveSO,其实例结构默认名字为fileName指定的名字
[CreateAssetMenu(fileName = "LoadData", menuName = "Load/LoadFiles", order = 1)]
public class ArchiveSO : ScriptableObject
{
// 存档通常以多个存档形式存在,而这里我们使用list对其进行填充
public List<LoadFile> loadFileList = new List<LoadFile>();
}
/// 假定LoadFile为游戏存档所需的基本信息,使其序列化(这能更好进行手动添加或者移除所实例出来的对象)
[System.Serializable]
public class LoadFile
{
// 游戏存档所需的基本配置,这里模拟当前等级,血量,和位置
public int currentLevel;
public float currentHP;
public Vector3 location;
// 自定义构造函数
public LoadFile(int currentLevel, float currentHp, Vector3 location)
{
this.currentLevel = currentLevel;
currentHP = currentHp;
this.location = location;
}
}
右键
->创建
->load
->loadFiles
因为我的unity有汉语包因此load被翻译成加载,其并不会影响导向,但是还是建议有个很好的区分名
其后我们可以在本地进行存档的手动填充和修改
2.创建存档管理脚本
我创建了LoadManager
脚本以控制基本存档的新增
、加载
、删除
、修改
using UnityEngine;
public class LoadManager : MonoBehaviour
{
// 模拟创建新开始所需参数
private int leve=1;
private float health=100;
private Vector3 location = new Vector3(0, 0, 0);
// ArchiveSTB声明
public ArchiveSO archiveSo;
// 新游戏,自动创建一个新存档
public void NewGame()
{
LoadFile newLoadFile = new LoadFile(leve,health,location);
archiveSo.loadFileList.Add(newLoadFile);
Debug.Log("新游戏存档创建成功");
}
// 加载游戏,默认加载存档最新
public void LoadGame()
{
// 检查是否有最新文档,没有则,创建新文档
if (archiveSo.loadFileList.Count != 0)
{
Debug.Log("当前等级:" + archiveSo.loadFileList[^1].currentLevel);
Debug.Log("当前血量:" + archiveSo.loadFileList[^1].currentHP);
Debug.Log("当前位置:" + archiveSo.loadFileList[^1].location);
}else NewGame();
}
// 删除存档,默认删除最后一条存档
public void DelLoad()
{
// 判定是否有可用存档
if (archiveSo.loadFileList.Count != 0)
{
archiveSo.loadFileList.RemoveAt(archiveSo.loadFileList.Count - 1);
}
}
// 修改存档,默认修改最新存档等级使其变成Lv:10
public void ModifyLoad()
{
archiveSo.loadFileList[^1].currentLevel = 10;
Debug.Log("当前等级已修改成:"+archiveSo.loadFileList[^1].currentLevel);
}
}
3.基本绑定与调试
二、背包系统1
如存档系统相近,需要设定好背包物品的存储信息,之后再进行相关的管理脚本设定,以下是一个简单的背包内物品使用ScriptableObject
方式来管理背包物品和查看物品信息.
1. 基本UI布局
布局草图如下,对应颜色为:
黑色:bg
橙色:Left
红色:Scroll View
蓝色:Right
灰色:Item Icon
绿色:Info Area
黄色:Btn
效果和层级图如下:
ps:通常而言item项多是预制体通过代码动态创建,而在此处之为了方便演示选择手动填充相应数量的item项
2. 创建ScriptableObject子类
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "BagItemsData", menuName = "BagItems/BagItem", order = 2)]
public class BagItemsSO : ScriptableObject
{
public List<BagItem> bagItemList = new List<BagItem>();
}
// 背包物品类,用于定义背包物品的基本属性,其中这里演示包含所需的图标、是否为装备
[System.Serializable]
public class BagItem
{
public Sprite itemIcon;
public string itemName;
[TextArea]
public String itemInfo;
public bool isEquipment;
}
创建一个名为BagItemsSO
的ScriptableObject
子类并同上述存档操作一致,创建出相应的可序列化数据结构,并进行相关配置
3. 创建管理逻辑脚本
1. Item物品类脚本
using UnityEngine;
using UnityEngine.UI;
public class Item : MonoBehaviour
{
// 获取Toggle组件
private Toggle _toggle;
// 公开基本物品参数,
public Image itemIcon;
public Text itemName;
public string itemInfo;
public bool isEquipment;
// 展示面板信息绑定
public Image showIcon;
public Text showInfo;
public Text showTip;
private void Start()
{
_toggle = GetComponent<Toggle>();
_toggle.onValueChanged.AddListener(b => UpdateInfoPanel());
}
// 更新信息面板函数
public void UpdateInfoPanel()
{
showIcon.sprite = itemIcon.sprite;
showInfo.text = itemInfo;
showTip.text = isEquipment ? "装备" : "使用";
}
}
Item
脚本由于挂载在Item物品类对象上,定义了基本的物品信息和展示界面相关的GameObject
组件,用于之后的点击互动展示
2. BagItems背包物品类脚本
using UnityEngine;
public class BagItems : MonoBehaviour
{
public BagItemsSO bagItemsSo;
private Item _itemScript;
private void Start()
{
// 更新填充Item脚本的属性
for (int i = 0; i < transform.childCount; i++)
{
_itemScript = transform.GetChild(i).GetComponent<Item>();
_itemScript.itemIcon.sprite = bagItemsSo.bagItemList[i].itemIcon;
_itemScript.itemName.text = bagItemsSo.bagItemList[i].itemName;
_itemScript.itemInfo = bagItemsSo.bagItemList[i].itemInfo;
_itemScript.isEquipment = bagItemsSo.bagItemList[i].isEquipment;
}
}
}
BagItems
脚本挂载在Scroll View
下的Content