如何使用 Unity 的 ScriptableObjects 和 Resources 系统来创建一个简易的数据库系统,用于存储和管理游戏数据。

1. 引言

  • 问题: 如何在 Unity 中存储数据?
  • 解决方案: 使用 ScriptableObjects 和 Resources 系统创建一个易于使用和管理的数据库。
  • 优势:
    • 自动读写数据
    • 自动处理资源实例化和更改
    • 无需额外插件
    • 使用用户定义键进行访问
    • 可扩展性强

2. 实现

2.1 项目结构

四个主要的脚本:

  • ItemData.cs: 定义了一个 ScriptableObject 类,用于存储物品数据,例如 ID、名称、等级和图标。
  • DataManager.cs: 定义了一个抽象类,用于管理数据,包括读取、添加和删除数据项。
  • ItemDataManager.cs: 继承自 DataManager 类,并实现了具体的数据管理逻辑,例如从 Resources 文件夹加载物品数据。
  • InventoryTestContext.cs: 用于测试数据库功能,打印所有物品信息。

2.2 ScriptableObjects

  • ScriptableObjects 用于在 Unity 中存储数据到资源文件夹中,可以通过代码进行读写和修改。
  • 使用 [CreateAssetMenu] 属性可以创建自定义菜单项,用于在编辑器中创建 ScriptableObject 对象。
  • 警告:不建议在游戏运行时通过代码修改 ScriptableObject 中的字段,可能会导致编辑器中出现奇怪的行为。

2.3 创建对象数据:Scriptable Object Item.cs 脚本

  • ItemData 类继承自 ScriptableObject,并定义了四个属性:id、displayName、levelRequired 和 icon。
  • 使用 [SerializeField] 属性使属性在编辑器中可见并可编辑。
  • 提供了相应的 getter 和 setter 方法。

ItemData.cs:

using System.Globalization;
using UnityEngine;

namespace DatabaseSystem.ScriptableObjects 
{
    [CreateAssetMenu(menuName = "Demo/Items/Item Data")]
    public class ItemData : ScriptableObject
    {
        #region 变量
        [SerializeField] private int id = default;
        [SerializeField] private string displayName = default;
        [SerializeField] private int levelRequired = default;
        [SerializeField] private Sprite icon = default;

        public int Id 
        {
            get { return id; }
            set { id = value; }
        }

        public string DisplayName 
        {
            set { displayName = value; }
            get { return displayName; }
        }

        public int LevelRequired
        { 
            get { return levelRequired; } 
            set {  levelRequired = value; } 
        }
        public Sprite Icon 
        {
            get { return icon; }
            set { icon = value; } 
        }
        #endregion
    }
}

2.4 编写 ItemDataManager 代码

  • DataManager 类是一个抽象类,定义了数据管理的基本方法,例如 GetAllDataObjects、GetDataObject、TryPutDataItem 和 TryRemoveItem。
  • ItemDataManager 类继承自 DataManager 类,并实现了具体的数据管理逻辑。
  • LoadFromResources 方法从 Resources 文件夹加载所有物品数据,并将其存储在字典中。
  • Initialize 方法用于初始化数据管理器。

DataManager.cs:

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

namespace DatabaseSystem.Managers
{
    // T 表示key类型,D 表示ItemDat的类型
    public abstract class DataManager<T, D> : MonoBehaviour
    {
        #region Variables
        protected Dictionary<T, D> dataDictionary = default;
        #endregion

        #region Public Methods
        public Dictionary<T, D> GetAllDataObjects()
        {
            return dataDictionary.ToDictionary(k => k.Key, v => v.Value);
        }
        public D GetDataObject(T id)
        {
            if(dataDictionary.ContainsKey(id))
            {
                return dataDictionary[id];
            }

            return default;
        }
        #endregion

        #region Protected Methods
        protected virtual bool TryPutDataItem(T id, D data)
        {
            if (dataDictionary.ContainsKey(id))
            {
                return false;
            }

            dataDictionary.Add(id, data);
            return true;
        }
        protected virtual bool TryRemoveItem(T id, D data)
        {
            if (!dataDictionary.ContainsKey(id))
            {
                return false;
            }

            dataDictionary.Remove(id);
            return true;
        }
        #endregion
    }
}

ItemDataManager:

using DatabaseSystem.ScriptableObjects;
using System.Collections.Generic;
using UnityEngine;

namespace DatabaseSystem.Managers
{
    public class ItemsDataManager : DataManager<int, ItemData>
    {
        #region Variables
        [SerializeField] private string resourcesItemsFolder = default;
        #endregion

        #region Private Methods
        private void LoadFromResources()
        {
            dataDictionary = new Dictionary<int, ItemData>();
            ItemData[] itemsFromResources = Resources.LoadAll<ItemData>(resourcesItemsFolder);
            foreach (var itemData in itemsFromResources)
            {
                TryPutDataItem(itemData.Id, itemData);
            }
        }
        #endregion

        #region Public Methods
        public void Initialize()
        {
            LoadFromResources();
        }
        #endregion
    }
}

2.5 在数据清单中使用数据库

  • 创建两个空物体,分别为其添加 ItemDataManager.cs 和 InventoryTestContext.cs 组件。
  • InventoryTestContext 组件负责初始化 ItemDataManager,并打印所有物品信息。

3. 总结

InventoryTestContext.cs:

  • 使用 ScriptableObjects 和 Resources 系统可以轻松创建一个可扩展的数据库系统。
  • 这种方法可以用于存储各种类型的数据,简化游戏开发流程。

其他要点

  • 警告:序列化成 json 格式时,需要注意字段是否可序列化。
  • DataManager 类可以进行扩展,以支持更多类型的数据。
posted @   多见多闻  阅读(94)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2022-07-12 JS实现Html File控件赋值
2022-07-12 C#中使用命名管道进行进程通信的实例
2022-07-12 System.IO之使用管道在进程间通信 (System.IO.Pipes使用)
2022-07-12 C# 简单的进程间通信方式,唤醒最小化到托盘的程序
2022-07-12 WPF之全局快捷键
2022-07-12 【WPF】只允许运行一个程序(单例)
点击右上角即可分享
微信分享提示