【Unity笔记】Unity开发笔记:ScriptableObject实现高效游戏配置管理(含源码解析)
在Unity开发中,高效管理游戏配置数据是提升开发效率的关键。本文分享如何使用ScriptableObject
构建可编辑的键值对存储系统,并实现运行时动态读取。
一、为什么选择ScriptableObject?
1.1 ScriptableObject的核心优势
- 独立资源:数据以
.asset
文件形式存在,不依赖场景对象 - 可视化编辑:直接在Inspector面板修改数据,无需代码重新编译
- 内存友好:数据按需加载,避免内存冗余
- 跨场景共享:一份数据资源可被多个场景复用
1.2 对比其他存储方案
方案 | 优点 | 缺点 |
---|---|---|
ScriptableObject | 实时编辑,类型安全 | 需要编写管理类 |
JSON/XML | 易读,跨平台 | 需要处理序列化/反序列化 |
PlayerPrefs | 简单易用 | 仅适合存储简单用户设置 |
数据库 | 处理复杂关系 | 过度设计,移动端性能开销大 |
二、实现键值对存储系统
2.1 基础数据结构定义
[System.Serializable]
public class GameKeyValue
{[Tooltip("配置项的唯一标识")] public string Key;[Tooltip("配置项的具体值")]public string Value;[TextArea][Tooltip("配置项描述(可选)")] public string Description;
}
2.2 创建ScriptableObject数据容器
[CreateAssetMenu(menuName = "Game Data/KeyValue Config", fileName = "GameConfig")]
public class GameConfig : ScriptableObject
{[SerializeField] private List<GameKeyValue> _entries = new List<GameKeyValue>();private Dictionary<string, string> _cachedDictionary;/// <summary>/// 通过Key获取Value(带缓存优化)/// </summary>public string GetValue(string key){InitializeDictionary();return _cachedDictionary.TryGetValue(key, out var value) ? value : null;}/// <summary>/// 初始化字典缓存(提升查询效率)/// </summary>private void InitializeDictionary(){if (_cachedDictionary != null) return;_cachedDictionary = new Dictionary<string, string>();foreach (var entry in _entries){if (string.IsNullOrEmpty(entry.Key)) continue;_cachedDictionary[entry.Key] = entry.Value;}}
}
代码亮点:
- 使用字典缓存提升查询效率(O(1)时间复杂度)
- 添加字段验证和注释说明
- 支持可选描述字段
三、数据管理最佳实践
3.1 创建配置文件
- 右键点击Project窗口
- Create → Game Data → KeyValue Config
- 重命名为
GameConfig.asset
![创建配置文件的Unity编辑器截图示意]
3.2 安全访问策略
public class GameConfigManager : MonoBehaviour
{[SerializeField] private GameConfig _configFile;private static GameConfigManager _instance;public static bool TryGetValue(string key, out string value){value = null;if (_instance == null || _instance._configFile == null){Debug.LogError("配置管理器未初始化!");return false;}value = _instance._configFile.GetValue(key);return !string.IsNullOrEmpty(value);}private void Awake(){if (_instance != null){Destroy(gameObject);return;}_instance = this;DontDestroyOnLoad(gameObject);// 预加载配置if (_configFile == null)_configFile = Resources.Load<GameConfig>("GameConfig");}
}
实现特性:
- 单例模式保证全局访问
- 自动加载Resources默认配置
- 防重复创建机制
- 跨场景持久化
四、实战应用示例
4.1 角色属性配置
public class CharacterLoader : MonoBehaviour
{[Header("角色配置")][SerializeField] private string _hpKey = "PLAYER_HP";[SerializeField] private string _speedKey = "PLAYER_SPEED";void Start(){if (GameConfigManager.TryGetValue(_hpKey, out var hpValue)){float hp = float.Parse(hpValue);GetComponent<Health>().Initialize(hp);}if (GameConfigManager.TryGetValue(_speedKey, out var speedValue)){float speed = float.Parse(speedValue);GetComponent<Movement>().SetSpeed(speed);}}
}
4.2 本地化文本系统
public class LocalizationSystem : MonoBehaviour
{private static Dictionary<string, string> _localizationDict;public static string GetText(string key){if (_localizationDict == null)LoadLocalization();return _localizationDict.TryGetValue(key, out var text) ? text : $"MISSING: {key}";}private static void LoadLocalization(){_localizationDict = new Dictionary<string, string>();if (!GameConfigManager.TryGetValue("LANG_CODE", out var langCode))langCode = "EN";var entries = GameConfigManager.GetAllEntries().Where(e => e.Key.StartsWith($"{langCode}_")).ToList();foreach (var entry in entries){var cleanKey = entry.Key.Substring(langCode.Length + 1);_localizationDict[cleanKey] = entry.Value;}}
}
五、高级技巧与注意事项
5.1 数据安全建议
- 数据校验:添加属性验证逻辑
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(GameConfig))]
public class GameConfigEditor : Editor
{public override void OnInspectorGUI(){var config = target as GameConfig;// 检查重复Keyvar keys = config.Entries.Select(e => e.Key).ToList();var duplicates = keys.GroupBy(x => x).Where(g => g.Count() > 1).Select(g => g.Key);if (duplicates.Any()){EditorGUILayout.HelpBox($"发现重复Key: {string.Join(", ", duplicates)}", MessageType.Error);}base.OnInspectorGUI();}
}
#endif
- 数据加密:对敏感配置进行AES加密
- 版本控制:使用[System.Version]标记数据版本
5.2 性能优化
- 分块加载:将大型配置拆分多个ScriptableObject
- 异步加载:通过Addressables系统实现按需加载
- 内存监控:定期清理未使用的配置数据
六、扩展应用方向
6.1 支持多数据类型
[System.Serializable]
public class TypedGameValue
{public string Key;public ValueType Type;public string StringValue;public float FloatValue;public bool BoolValue;public enum ValueType { String, Float, Bool }public object GetValue(){return Type switch{ValueType.String => StringValue,ValueType.Float => FloatValue,ValueType.Bool => BoolValue,_ => null};}
}
6.2 配置热更新方案
- 通过UnityWebRequest下载最新配置
- 使用JsonUtility反序列化更新ScriptableObject
- 配合版本号校验实现增量更新
七、常见问题解答
Q1:数据在真机上修改后能否保存?
- 编辑器环境下修改会持久化,但构建后需要通过代码实现运行时修改和保存
Q2:如何防止非技术人员误删配置?
- 使用Custom Editor隐藏删除按钮
- 设置配置文件为ReadOnly模式
Q3:配置项太多如何快速查找?
- 实现搜索过滤功能
// Editor扩展代码
var searchText = EditorGUILayout.TextField("Search", _searchText);
var filtered = config.Entries.Where(e => e.Key.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||e.Description.Contains(searchText, StringComparison.OrdinalIgnoreCase)
).ToList();
八、总结
通过本教程,我们实现了:
- 基于ScriptableObject的可视化配置系统 ✅
- 高效安全的配置访问机制 ✅
- 可扩展的多场景应用方案 ✅
- 企业级数据管理最佳实践 ✅
下一步建议:
- 尝试集成到现有项目中
- 扩展支持数组类型配置
- 实现配置差异对比工具
欢迎在评论区交流! 🚀
相关文章:
【Unity笔记】Unity开发笔记:ScriptableObject实现高效游戏配置管理(含源码解析)
在Unity开发中,高效管理游戏配置数据是提升开发效率的关键。本文分享如何使用ScriptableObject构建可编辑的键值对存储系统,并实现运行时动态读取。 一、为什么选择ScriptableObject? 1.1 ScriptableObject的核心优势 独立资源:…...
FPAG IP核调用小练习
一、调用步骤 1、打开Quartus 右上角搜索ROM,如图所示 2、点击后会弹出如图所示 其中文件路径需要选择你自己的 3、点击OK弹出如图所示 图中红色改为12与1024 4、然后一直点NEXT,直到下图 这里要选择后缀为 .mif的文件 5、用C语言生成 .mif文件 //…...
vue动画
1、动画实现 (1)、操作css的transition或animation (2)、在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名 (3)、过渡的相关类名: xxx-enter-active: 进入的时候激活…...
大数据学习(106)-hivesql函数
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
AI日报 - 2025年04月16日
🌟 今日概览(60秒速览) ▎🤖 模型井喷 | OpenAI (o3/o4-mini, GPT-4.1), Meta (Llama 4 Scout/Maverick), Z.ai (GLM-4家族), Cohere (Embed 4), Google (DolphinGemma) 等发布新模型,多模态、长文本、高效推理成焦点。 ▎💼 商业…...
C# 经纬度坐标的精度及WGS84(谷歌)、GCJ02(高德)、BD09(百度)坐标相互转换(含高精度转换)
1. 概述 WGS-84坐标系(World Geodetic System一1984 Coordinate System)是一种国际上采用的地心坐标系,GCJ-02是由中国国家测绘局(G表示Guojia国家,C表示Cehui测绘,J表示Ju局)制订的地理信息系…...
案例:陌陌聊天数据分析
背景分析: 陌陌作为聊天平台每天都会有大量的用户在线,会出现大量的聊天数据,通过对 聊天数据的统计分析 ,可以更好的 对用户构建精准的 用户画像 ,为用户提供更好的服务以及实现 高 ROI 的平台运营推广ÿ…...
关闭谷歌浏览器(Google Chrome)的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。
关闭谷歌浏览器(Google Chrome)的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。 1. 在 Windows 上关闭 Chrome 自动更新2. 在 macOS 上关闭 Chrome 自动更新3. 在 Linux 上关闭 Chrome 自动更新4. 注意事项1. 在 Windows 上关闭 Chro…...
进程(完)
今天我们就补充一个小的知识点,查看进程树命令,来结束我们对linux进程的学习,那么话不多说,来看. 查看进程树 pstree 基本语法: pstree [选项] 优点:可以更加直观的来查看进程信息 常用选项: -p:显示进程的pid -uÿ…...
(劳特巴赫调试器学习笔记)四、Practice脚本.cmm文件编写
Lauterbach调试器 文章目录 Lauterbach调试器一、什么是Practice脚本文件二、cmm脚本使用示例总结 一、什么是Practice脚本文件 官方文档解释: 因为Practice脚本以cmm为后缀,所以大多数人叫它cmm脚本。 以tricore为例,在安装目录下ÿ…...
并行流parallelStream.map().collect()
一、使用场景 先贴代码 public static void main(String[] args) {List<String> stringList new ArrayList<>();List<Integer> integerList new ArrayList<>();int num 10000;for (int i 0;i<num;i){stringList.add(String.valueOf(i));}stri…...
2025最新版flink2.0.0安装教程(保姆级)
Flink支持多种安装模式。 local(本地)——本地模式 standalone——独立模式,Flink自带集群,开发测试环境使用 standaloneHA—独立集群高可用模式,Flink自带集群,开发测试环境使用 yarn——计算资源统一…...
软件测试小讲
大家好,我是程序员小羊! 前言: 在 Web 项目开发中,全面的测试是保证系统稳定性、功能完整性和良好用户体验的关键。下面是一个详细的 Web 项目测试点列表,涵盖了不同方面的测试: 1. 功能测试 确保应用…...
DP35 【模板】二维前缀和 ---- 前缀和
目录 一:题目 二:算法原理 三:代码实现 一:题目 题目链接:【模板】二维前缀和_牛客题霸_牛客网 二:算法原理 三:代码实现 #include <iostream> #include <vector> using name…...
C语言——分支语句
在现实生活中,我们经常会遇到作出选择和判断的时候,在C语言中也同样要面临作出选择和判断的时候,所以今天,就让我们一起来了解一下,C语言是如何作出选择判断的。 目录 1.何为语句? 2.if语句 2.1 if语句的…...
使用Docker安装Jenkins
1、准备 2、安装 详见: https://www.jenkins.io/doc/book/installing/ https://www.jenkins.io/zh/doc/book/installing/ https://www.jenkins-zh.cn/tutorial/get-started/install/ # 方式1: # 详见:https://www.jenkins.io/doc/book/inst…...
东方博宜OJ ——2395 - 部分背包问题
贪心入门 ————2395 - 部分背包问题 2395 - 部分背包问题题目描述输入输出样例问题分析贪心算法思路代码实现总结 2395 - 部分背包问题 题目描述 阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N (N < 100)堆金币,第i堆金币的总重量和总价值分别是mi,vi (l …...
【期中准备特辑】计组,电路,信号
计组 以点带面地复习书中内容! 指令体系结构(ISA)是计算机硬件和软件的分界面 世界上第一台电子计算机是 ENIAC(埃尼阿克) 第一代计算机采用电子管作为主要器件;第二代计算机采用晶体管;第三代…...
经典算法 判断一个图是不是树
判断一个图是不是树 问题描述 给一个以0 0结尾的整数对列表,除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图是不是树。是输出YES,不是输出NO。 输入样例1 6 8 5 3 5 2 6 4 5…...
力扣 283 移动零的两种高效解法详解
目录 方法一:两次遍历法 方法二:单次遍历交换法 两种方法对比 在解决数组中的零移动到末尾的问题时,我们需要保持非零元素的顺序,并原地修改数组。以下是两种高效的解法及其详细分析。 方法一:两次遍历法 思路分析…...
代码随想录第18天:二叉树
一、修剪二叉树(Leetcode 669) 递归法 class Solution:def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:# 如果当前节点为空,直接返回空节点(递归终止条件)if root is None:return None# 如果…...
KMP算法核心笔记:前后缀本质与nextval实现
KMP算法核心笔记:前后缀本质与nextval实现 核心疑问:为什么用「前后缀」而非「最大子串」? 1. 结构唯一性 前后缀限定在字符串首尾区域,最大子串可位于任意位置只有前后缀能保证滑动后的有效对齐 2. 移动确定性 文本…...
Breeze 40A FOC 电调:Vfast 观测器技术赋能无人机精准动力控制
核心技术特性 1. 全新Vfast 观测器技术 基于先进矢量控制算法(FOC 驱动),实现电机状态实时精准观测,适配性优于传统 FOC 方案,兼容主流无人机动力配置。高效算法设计,输出功率与力效超越多数方波电调&…...
如何处理ONLYOFFICE文档服务器与Java Web应用间的安全认证和授权
如何处理ONLYOFFICE文档服务器与Java Web应用间的安全认证和授权? 处理 ONLYOFFICE 文档服务器与 Java Web 应用之间的安全认证和授权,通常涉及以下几个关键步骤和技术: 1. JWT (JSON Web Token) 认证 启用 JWT: ONLYOFFICE 文档…...
手机上的PDF精简版:随时随地享受阅读
在移动互联网时代,随时随地阅读电子书和文档已经成为许多人的习惯。无论是学习、工作还是娱乐,一款好用的PDF阅读器都是必不可少的工具。今天,我们要介绍的 思读PDF精简版,就是这样一款简洁而强大的PDF阅读工具,能够让…...
XCTF-web(一)
view_source F12ctrluctrlshiftiURL前添加:view-source:curl http://192.168.1.1robots 根据题目提示,查看一下robots.txt /flag_ls_h3re.php backup /index.php.bak ┌──(kali㉿kali)-[~] └─$ cat index.php.bak <html> <…...
字节跳动开源 Godel-Rescheduler:适用于云原生系统的全局最优重调度框架
背景 在云原生调度中,一次调度往往无法解决所有问题,需要配合重调度来优化资源分配和任务摆放。传统的重调度框架主要集中在识别异常节点或任务,并通过迁移或删除来解决。然而,这些框架往往只能解决局部问题,无法提供…...
贪心算法day9(合并区间)
1.合并区间 56. 合并区间 - 力扣(LeetCode) 对于这种区间问题,我们应该先排序根据排序的结果总结一些规律,进而的得出解决该问题的策略。 class Solution {public static int[][] merge(int[][] intervals) {//第一步进行左端点…...
插件化设计,打造个性化音乐体验!
打工人们你们好!这里是摸鱼 特供版~ 今天给大家带来一款超酷的音乐播放器——MusicFree,它不仅功能强大,还支持插件化设计,让你的音乐体验更加个性化! 推荐指数:★★★★★ 1. 插件化设计 功能强大&#…...
深入解析分类模型评估指标:ROC曲线、AUC值、F1分数与分类报告
标题:深入解析分类模型评估指标:ROC曲线、AUC值、F1分数与分类报告 摘要: 在机器学习中,评估分类模型的性能是至关重要的一步。本文详细介绍了四个核心评估指标:ROC曲线、AUC值、F1分数和分类报告。通过对比这些指标…...
2025第16届蓝桥杯省赛之研究生组F题01串求解
2025第16届蓝桥杯省赛之研究生组F题01串求解 一、题目概述二、解题思路2.1题目分析2.2解题思路 三、求解代码3.1求解步骤3.1.1求解x所在的二进制位数区间3.1.2求解总位数为cnt的含1数3.1.3求解cnt1~x之间的含1数 3.2完整代码3.3代码验证 四、小结 一、题目概述 给定一个由0,1,…...
【2-10】E1与T1
前言 之前我们简单介绍了人类从电话线思维到如今的数据报分组交换思维过渡时期的各种技术产物,今天我们重点介绍 E1/T1技术。 文章目录 前言1. 产生背景2. T13. E14. SONET4.1 OC-14.2 OC-3 及其它 5. SDH5.1. STM-1 6. SONET VS SDH后记修改记录 1. 产生背景 E1/…...
2025 年蓝桥杯 Java B 组真题解析分享
今年是我第二次参加蓝桥杯软件类Java B组的比赛,虽然赛前做了不少准备,但真正坐在考场上时,还是有种熟悉又紧张的感觉。蓝桥杯的题目一向以“基础创新”著称,今年也不例外,每道题都考验着我们对算法的理解、代码实现能…...
IMX6ULL2025年最新部署方案2在Ubuntu24.04上编译通过Qt5.12.9且部署到IMX6ULL正点原子开发板上
IMX6ULL2025年最新部署方案2:在Ubuntu24.04上编译通过Qt5.12.9且部署到IMX6ULL正点原子开发板上 前言 本篇方案部署是笔者这几天除了打蓝桥杯以外,笔者在研究的东西,现在写道这里的时候,笔者已经成功的在Ubuntu24.04上,使用默…...
通过微信APPID获取小程序名称
进入微信公众平台,登录自己的小程序后台管理端,在“账号设置”中找到“第三方设置” 在“第三方设置”页面中,将页面拉到最下面,即可通过appid获取到这个小程序的名称信息...
混合开发部署实战:PyInstaller + .NET 8 + Docker全链路配置
文章目录 一、PyInstaller打包Python环境1. 基础打包(Linux环境)2. 高级配置3. 验证打包结果 二、.NET 8与Python的集成模式1. 进程调用(推荐方案)2. REST API通信 三、Docker多阶段构建配置1. 完整Dockerfile示例2. 关键配置解析…...
使用 Sass 打造动态星空背景效果
在前端开发中,视觉效果越来越受到重视。本文将通过一个生动的示例,讲解如何利用 Sass 构建一个具有动态星空滚动效果的背景页面,同时也系统介绍 Sass 的核心功能与实践技巧。 一、Sass 的作用 Sass(Syntactically Awesome Style …...
低空经济有哪些GIS相关岗位?
在低空经济中,GIS(地理信息系统)技术发挥着重要作用。GIS开发工程师负责开发、维护和优化与低空经济相关的GIS系统,如无人机起降场布局、空域管理、气象监测等。一般会参与二、三维GIS项目数据处理与前端开发,以及相关…...
Python 垃圾回收机制全解析:内存释放与优化
在编写高效、稳定的 Python 程序时,内存管理往往是一个被忽视但至关重要的领域。对于 Python 开发者来说,最初的学习曲线通常集中在语法、库使用和应用框架上,而对于内存管理和垃圾回收(GC,Garbage Collection…...
性能优化实践
4.1 大规模量子态处理的性能优化 背景与问题分析 量子计算中的大规模量子态处理(如量子模拟、量子态可视化)需要高效计算和实时渲染能力。传统图形API(如WebGL)在处理高维度量子态时可能面临性能瓶颈,甚至崩溃(如表格中14量子比特时WebGL的崩溃)。而现代API(如WebGPU…...
opentelemetry笔记
span https://github.com/open-telemetry/opentelemetry-cpp/blob/f987c9c094f276336569eeea85f17e361de5e518/sdk/src/trace/span.h 在 OpenTelemetry C 的 sdk/src/trace 目录中,不同的 span 定义和实现是为了支持追踪(Tracing)功能的多样…...
【JavaScript】二十一、日期对象
文章目录 1、实例化日期对象2、相关方法3、时间戳4、案例:毕业🎓倒计时效果 1、实例化日期对象 获得当前时间 const date new Date()获得指定时间 const date new Date(2025-4-14 20:46:00) console.log(date)2、相关方法 方法作用说明getFullYear…...
GIT工具学习【1】:新安装git预操作
目录 1.写在前面2.为常用指令配置别名3.初始化4.解决中文乱码问题 1.写在前面 新安装git命令后,需要一些设置会用的比较的顺畅。 这篇文章只要跟着做即可,至于原理,后面会写清楚的。 2.为常用指令配置别名 #新建一个.bashrc touch ~/.bash…...
docker安装ES
ES安装步骤 1. 创建docker网络,使其docker内部通信 2. 下载 | 导入镜像文件(ES Kibana) 3. 创建容器,并访问 4. 安装Ik分词器(es对中文并不友好,所以需要安装IK分词使其适配中文) 1. 创建docke…...
【控制学】控制学分类
【控制学】控制学分类 文章目录 [TOC](文章目录) 前言一、工程控制论1. 经典控制理论2. 现代控制理论 二、生物控制论三、经济控制论总结 前言 控制学是物理、数学与工程的桥梁 提示:以下是本篇文章正文内容,下面案例可供参考 一、工程控制论 1. 经典…...
人工智能应用开发中常见的 工具、框架、平台 的分类、详细介绍及对比
以下是人工智能应用开发中常见的 工具、框架、平台 的分类、详细介绍及对比: 一、工具(Tools) 定义:用于完成特定任务的软件或库,通常专注于开发流程中的某个环节(如数据处理、模型调试、部署等ÿ…...
Linux磁盘格式化(mkfs、mkfs.xfs、mkfs.ext4)、Linux文件系统的校验(xfs_repair、fsck_ext4)
在Linux系统中,磁盘格式化和文件系统校验是系统管理的重要任务。以下是关键步骤和命令的总结: 磁盘格式化 1. 选择文件系统类型 XFS:适用于大文件和高并发场景,支持高性能和扩展性。ext4:成熟稳定的通用文件系统,适合大多数场景。2. 格式化命令 通用格式: sudo mkfs -…...
Android学习总结之git篇
Git 的原理时,你可以从数据结构、对象存储、引用管理、分支与合并等方面结合源码进行分析。以下是详细介绍: 1. 基本数据结构和对象存储 Git 底层主要基于四种对象来存储数据:blob(数据块)、tree(树&…...
Python基础语法——类型
目录 类型的意义动态类型静态类型 类型的意义 不同的类型,占用的内存空间是不同的. 占几个字节 int 默认是 4 个字节.动态扩容 float 固定 8 个字节 bool 一个字节就足够了 str 变长的 不同的类型,对应能够进行的操作也是不同的 int/float, “” “-” “ * ” “/”——不能使…...
vue2中基于el-select封装一个懒加载下拉框
需求 当下拉选项的数据量过大时,后端接口是分页格式返回数据。 解决方案 自定义封装一个懒加载下拉组件,每次滚动到底部时自动获取下一页数据,这样可有效防止数据量过大时造成组件卡顿。 具体实现步骤 1、创建懒加载下拉选择组件 <t…...