超越PlayerPrefs:当你的Unity游戏需要更专业的数据存储方案时

Unity(游戏)中五种数据存储的方法 Unity(游戏)中五种数据存储的方法 一、PlayerPrefs unity3d提供了一个用于本地持久化保存与读取的类-------PlayerPrefs.工作原理很简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值(注:PlayerPrefs运用起来很方便,随时都可以存取与读取)。 Playerprefs类支持3中数据类型的保存和读取,分别是浮点型、整型和字符串... 阅读详情

超越PlayerPrefs:当你的Unity游戏需要更专业的数据存储方案时

你是否还记得第一次在Unity里用PlayerPrefs.SetInt("Score", 100)保存玩家分数时的那种便捷感?对于原型开发、游戏设置或简单的进度标记,PlayerPrefs确实像一把瑞士军刀,轻巧顺手。然而,当你的项目从“我的第一个游戏”成长为拥有复杂角色系统、庞大的装备库、非线性的任务网以及需要云端同步的存档时,这把瑞士军刀就显得有些力不从心了。你会发现,数据莫名其妙地丢失、存档文件被玩家轻易修改、加载大量物品时卡顿明显……这些都不是Bug,而是选错了工具的信号。

对于中高级开发者而言,数据存储架构的决策,往往发生在项目从“能跑”到“要上线”的关键跃升阶段。此时,我们需要的不再是“够用”,而是“合适”与“健壮”。PlayerPrefs的局限性,恰恰是引导我们探索更专业存储方案的起点。本文将带你跳出PlayerPrefs的舒适区,深入剖析几种主流的替代方案——从结构化的JSON、二进制序列化,到轻量级数据库SQLite,乃至面向数据的解决方案。我们将不局限于简单的API对比,而是聚焦于性能边界、适用场景、架构成本与未来可扩展性,帮助你根据项目真实的规模与复杂度,做出明智的技术选型。

1. 重新审视:PlayerPrefs的“阿喀琉斯之踵”

在寻找替代方案之前,我们必须清晰地界定PlayerPrefs究竟在哪里会“摔跤”。许多开发者对其局限性的认识停留在“不能存复杂数据”的层面,这远远不够。

PlayerPrefs的本质,是Unity引擎对不同平台(Windows注册表、macOS plist文件、iOS NSUserDefaults等)简单键值存储接口的一层封装。它的设计初衷是保存用户的偏好设置,正如其名“Player Preferences”。当你试图用它承载游戏核心状态时,以下几个问题会逐一浮现:

  • 数据结构的苍白:它只支持int, float, string三种基础类型。任何自定义的类、列表、字典,都必须手动拆解、拼接、转换,这个过程不仅繁琐,而且极易出错。想象一下,你要保存一个包含生命值、装备列表、技能树和任务状态的PlayerData对象,用PlayerPrefs来实现将是怎样的噩梦。
  • 性能的隐形瓶颈:PlayerPrefs的每次Set操作,并非立即写入磁盘,但Save()的调用或游戏退出时的自动保存,会触发一次同步I/O操作。如果你在游戏过程中频繁保存(例如自动存档、每获得一件物品就保存),主线程可能会被这些I/O阻塞,导致帧率波动。更糟糕的是,所有数据存储在一个文件中,每次保存都是全量写入,数据量大了之后,开销不容忽视。
  • 安全性的“裸奔”:在PC和安卓平台,PlayerPrefs存储的文件是明文或易于解码的。稍有经验的玩家就能找到存档文件,用文本编辑器修改分数、货币数量。对于单机游戏,这或许可以接受;但对于任何涉及内购、排行榜或玩家间竞争的元素,这无疑是灾难。
  • 数据管理的混乱:缺乏版本管理、数据迁移和结构化查询能力。当游戏更新,需要调整保存的数据结构时,如何平滑地迁移旧存档?如何快速查询所有“已完成A任务但未开启B任务的玩家”数据?PlayerPrefs对此无能为力。

注意:不要误会,指出这些局限并非全盘否定PlayerPrefs。对于音量、画质、键位绑定、语言选择这类真正的“偏好设置”,它依然是首选,简单且直接。问题的关键在于区分“配置”与“状态”。

为了更直观地对比,我们来看一个简单场景下的数据存储示例:

假设我们需要保存一个玩家角色基础信息,包含名称、等级和经验值。

使用PlayerPrefs的典型代码:

// 存储
PlayerPrefs.SetString("PlayerName", "Rookie");
PlayerPrefs.SetInt("PlayerLevel", 10);
PlayerPrefs.SetInt("PlayerExp", 4550);
PlayerPrefs.Save();

// 读取
string name = PlayerPrefs.GetString("PlayerName", "Default");
int level = PlayerPrefs.GetInt("PlayerLevel", 1);
int exp = PlayerPrefs.GetInt("PlayerExp", 0);

这种方式键名需要手动管理,容易拼写错误,且数据分散。

2. 结构化数据的救星:JSON与二进制序列化

当数据变得复杂,我们首先想到的是将整个对象“打包”存储。序列化(Serialization)正是这个过程:将内存中的对象状态转换为可存储或传输的格式。

2.1 JSON:可读、通用与跨平台的权衡

JSON(JavaScript Object Notation)已成为数据交换的事实标准。在Unity中,你可以使用Newtonsoft.Json(需导入)或Unity 2020.1后内置的UnityEngine.JsonUtility。

为什么选择JSON?

  • 人类可读:存档文件是文本,便于调试、手动修复(虽然不推荐)和理解数据结构。
  • 跨平台与跨语言:JSON格式通用,方便与后端服务器通信,或未来将存档数据迁移到其他工具链。
  • 良好的库支持:序列化/反序列化库成熟,能处理嵌套对象、列表和字典。

使用UnityEngine.JsonUtility的示例: 首先,定义你的数据类,并使用[System.Serializable]特性标记。

[System.Serializable]
public class PlayerData {
    public string playerName;
    public int level;
    public int experience;
    public List<string> inventoryItems; // PlayerPrefs无法直接存储的列表
    public Dictionary<string, int> questProgress; // 字典需要额外处理
}

// 序列化与保存
PlayerData data = new PlayerData();
data.playerName = "Rookie";
data.level = 10;
// ... 填充其他数据
string jsonString = JsonUtility.ToJson(data, true); // 第二个参数为true时美化输出
System.IO.File.WriteAllText(Application.persistentDataPath + "/playerData.json", jsonString);

// 读取与反序列化
if (System.IO.File.Exists(Application.persistentDataPath + "/playerData.json")) {
    string loadedJson = System.IO.File.ReadAllText(Application.persistentDataPath + "/playerData.json");
    PlayerData loadedData = JsonUtility.FromJson<PlayerData>(loadedJson);
}

JSON方案的局限性:

  • 性能开销:序列化(尤其是复杂的深层对象图)和字符串操作(读写文件)比二进制方式慢。
  • 存储空间:文本格式比二进制更占空间。
  • 安全性:依然是明文,敏感数据需额外加密。
  • JsonUtility的限制:无法直接序列化字典、多态类型,属性支持也有限。这时可能需要转向功能更全的Newtonsoft.Json。

2.2 二进制序列化:追求极致性能与尺寸

如果你对存档的读取速度、文件大小有极致要求,且不需要人类可读,二进制序列化是更好的选择。.NET提供了BinaryFormatter,但请注意,由于其安全漏洞,微软已将其标记为“不安全”,不推荐在新项目中使用。更现代的替代品是System.Text.Json(配合自定义转换器)或第三方库如MessagePack。

以MessagePack-CSharp为例: MessagePack是一种高效的二进制序列化格式,速度极快,体积小巧。

  1. 安装:通过Unity的Package Manager或NuGet安装MessagePack。
  2. 标记数据类:
    [MessagePackObject]
    public class PlayerData {
        [Key(0)]
        public string PlayerName { get; set; }
        [Key(1)]
        public int Level { get; set; }
        [Key(2)]
        public List<string> InventoryItems { get; set; }
    }
    
  3. 序列化与保存:
    using MessagePack;
    
    PlayerData data = new PlayerData { PlayerName = "Rookie", Level = 10 };
    byte[] bytes = MessagePackSerializer.Serialize(data);
    System.IO.File.WriteAllBytes(Application.persistentDataPath + "/playerData.msgpack", bytes);
    
    // 读取
    byte[] loadedBytes = System.IO.File.ReadAllBytes(Application.persistentDataPath + "/playerData.msgpack");
    PlayerData loadedData = MessagePackSerializer.Deserialize<PlayerData>(loadedBytes);
    

二进制序列化的优势与挑战:

  • 优势:极高的序列化/反序列化速度,极小的文件体积,天生的数据混淆(非加密,但增加了解读难度)。
  • 挑战:数据格式不透明,调试困难;版本兼容性需要精心管理(如使用[Key(N)]显式定义字段顺序);依赖特定的序列化库。

2.3 方案对比与选择建议

特性PlayerPrefsJSON (UnityEngine.JsonUtility)二进制 (如 MessagePack)
数据结构支持仅基础类型复杂对象、列表(字典受限)复杂对象、列表、字典等
可读性平台依赖,通常不可读高(文本格式)低(二进制格式)
性能简单数据快,大量数据慢中等非常高
文件大小小(键值对)较大(文本、格式字符)非常小
跨平台/语言仅Unity内极好好(需相同库)
安全性低低(明文)中(非明文,但非加密)
适用场景用户偏好设置、简单标记游戏存档、配置数据、需与Web服务交互的数据对性能/体积敏感的核心存档、网络同步数据包

选择建议:对于大多数单机或弱联网游戏的核心存档,JSON是一个平衡且安全的选择。它提供了足够的数据结构表达能力,良好的可调试性,以及应对未来数据迁移的灵活性。只有当性能或包体大小成为瓶颈时,才值得引入二进制序列化方案。

3. 引入关系型力量:SQLite本地数据库实战

当游戏数据不再是几个简单的对象,而是成百上千件物品、任务、角色,并且需要复杂的查询、关联和事务支持时,序列化单个大文件的方式会变得笨重。此时,一个嵌入式的本地数据库就显得尤为强大。SQLite是这一领域的王者,它无需单独服务器进程,整个数据库就是一个文件,却支持完整的SQL语法。

为什么在游戏里用SQLite?

  • 复杂查询:轻松实现“找出所有力量大于10的紫色品质武器”。
  • 关联数据:高效管理玩家、物品、任务之间的多对多关系。
  • 事务支持:确保存档操作的原子性,避免数据损坏。
  • 增量更新:只修改变化的数据,而非重写整个存档,效率更高。

3.1 在Unity中集成SQLite

Unity本身不包含SQLite,需要手动集成。最常用的方式是使用Mono.Data.Sqlite库(在Windows/Mac/Linux的Unity Editor中通常已存在)或通过DLL导入。

基础操作流程:

  1. 连接数据库:

    using Mono.Data.Sqlite;
    using System.Data;
    
    string connectionString = "URI=file:" + Application.persistentDataPath + "/gameSave.db";
    IDbConnection dbConnection = new SqliteConnection(connectionString);
    dbConnection.Open();
    
  2. 创建表(定义数据结构):

    IDbCommand dbCommand = dbConnection.CreateCommand();
    string createTableQuery = @"
        CREATE TABLE IF NOT EXISTS Player (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            level INTEGER DEFAULT 1,
            experience INTEGER DEFAULT 0
        );
        CREATE TABLE IF NOT EXISTS Inventory (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            player_id INTEGER,
            item_id INTEGER,
            quantity INTEGER,
            FOREIGN KEY (player_id) REFERENCES Player(id)
        );";
    dbCommand.CommandText = createTableQuery;
    dbCommand.ExecuteNonQuery();
    
  3. 插入与读取数据:

    // 插入玩家
    dbCommand.CommandText = "INSERT INTO Player (name, level) VALUES (@name, @level)";
    SqliteParameter nameParam = new SqliteParameter("@name", "Rookie");
    SqliteParameter levelParam = new SqliteParameter("@level", 10);
    dbCommand.Parameters.Add(nameParam);
    dbCommand.Parameters.Add(levelParam);
    dbCommand.ExecuteNonQuery();
    
    // 查询玩家
    dbCommand.CommandText = "SELECT * FROM Player WHERE level > @minLevel";
    dbCommand.Parameters.Clear();
    dbCommand.Parameters.Add(new SqliteParameter("@minLevel", 5));
    IDataReader reader = dbCommand.ExecuteReader();
    while (reader.Read()) {
        Debug.Log($"Player: {reader["name"]}, Level: {reader["level"]}");
    }
    reader.Close();
    
  4. 关闭连接:dbConnection.Close();

3.2 使用ORM层简化操作:以SQLite-net为例

直接写SQL命令虽然强大,但繁琐且容易出错。使用一个轻量级的ORM(对象关系映射)库可以极大提升开发效率。SQLite-net是一个极佳的选择。

using SQLite;

// 定义数据类作为表
[Table("Players")]
public class Player {
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    public int Level { get; set; }
    [Ignore] // 此属性不存入数据库
    public Vector3 Position { get; set; }
}

// 初始化数据库连接
string databasePath = Path.Combine(Application.persistentDataPath, "gameSave.db");
SQLiteConnection db = new SQLiteConnection(databasePath);

// 创建表(如果不存在)
db.CreateTable<Player>();

// 插入数据(对象形式)
Player newPlayer = new Player { Name = "Rookie", Level = 10 };
db.Insert(newPlayer);

// 查询数据(LINQ语法,非常直观)
var highLevelPlayers = db.Table<Player>().Where(p => p.Level > 5).ToList();
foreach (var player in highLevelPlayers) {
    Debug.Log(player.Name);
}

// 更新数据
var playerToUpdate = db.Table<Player>().First(p => p.Name == "Rookie");
playerToUpdate.Level = 11;
db.Update(playerToUpdate);

// 删除数据
db.Delete<Player>(playerToUpdate.Id);

SQLite方案的适用场景与成本:

  • 适用:大型RPG/沙盒游戏的物品库、任务系统;模拟经营类游戏的大量实体管理;需要复杂查询和报表的任何数据密集型游戏。
  • 成本:引入额外的库和依赖;需要学习基本的SQL或ORM知识;数据库文件的管理(备份、迁移、压缩)需要额外考虑。对于小型项目,这可能属于“杀鸡用牛刀”。

4. 架构升级:面向数据与混合存储策略

对于真正的大型、复杂的项目,单一的存储方案可能仍不够。我们需要从架构层面思考数据存储,采用混合策略,并拥抱面向数据的设计思路。

4.1 混合存储:各司其职

一个成熟的游戏项目,其数据是分层的,应采用不同的存储方式:

  • 玩家偏好设置(音量、键位):PlayerPrefs。这是它的本职工作,完美胜任。
  • 游戏核心存档(角色状态、世界进度):JSON序列化或二进制序列化。将整个游戏状态序列化为一个或几个大文件,结构清晰,加载方便。
  • 海量静态配置数据(物品属性、对话文本、关卡数据):可以放在ScriptableObject中用于开发,发布时打包成AssetBundle或序列化为二进制/JSON文件。甚至可以考虑用SQLite数据库文件来存储,便于策划用外部工具编辑。
  • 运行时产生的动态、关联性强的数据(公会成员关系、邮件系统、市场交易日志):SQLite。利用其强大的查询和事务能力。

关键在于设计一个统一的存档管理服务(SaveManager),对外提供简单的SaveGame()和LoadGame()接口,内部则根据数据类型分发到不同的存储后端。

4.2 面向数据的存储设计

现代游戏引擎如Unity的DOTS(面向数据的技术栈)强调数据的连续布局与高效处理。这种思想也可以影响存储设计。

  • 数据与行为分离:存储系统只关心纯数据(组件),不存储任何逻辑或方法。这使序列化更干净,也更容易进行版本迁移。
  • 考虑数据局部性:将同时存取的数据放在一起。例如,将角色的基础属性和其装备ID放在一个结构里序列化,而不是分散存储。
  • 设计可扩展的数据模式:使用版本号字段、可选字段或灵活的序列化方案(如JSON的灵活结构),以便在未来更新游戏时,能够兼容旧版本的存档。

4.3 不容忽视的附加议题

  • 加密与防篡改:对于JSON或二进制存档,可以使用AES等对称加密算法对整体文件或关键字段进行加密。对于SQLite,可以使用支持加密的版本(如SQLCipher)或对数据库文件整体加密。但记住,客户端没有绝对的安全,加密的目的是提高篡改门槛,而非绝对防止。
  • 版本迁移:在数据类中增加一个SaveVersion字段。加载存档时,检查版本号,如果低于当前版本,则调用相应的迁移函数,将旧数据结构转换为新结构。这是一个需要在一开始就规划好的重要功能。
  • 云存档与多设备同步:本地存储是基础,但现代游戏往往需要云存档。你可以将本地序列化后的存档文件(或SQLite数据库文件)整体上传到游戏服务器,或者设计一套更精细的、只同步差异数据的协议。这时,结构清晰、可序列化的本地数据格式就显得尤为重要。

在我参与过的一个中型Roguelike项目中,我们最初使用JSON存储所有数据。当玩家物品超过500件、关卡数据激增后,存档加载出现了明显的卡顿。我们将静态的、可查询的物品库和关卡数据迁移到了SQLite,而将动态的、结构化的玩家运行时状态保留为JSON。这次重构后,加载时间减少了70%,并且为策划人员提供了直接编辑数据库配置表的能力,大幅提升了开发效率。这个经历让我深刻体会到,没有“最好”的方案,只有“最适合”当前和可预见未来需求的组合拳。

Unity中游戏数据存储 游戏数据存储的方法很多,分本地和网络存储,本地存储有txt文件、json、PlayerPrefs、ScriptableObject和SQLite数据库读写等等;网络存储则是数据存储在服务器端,然后通过网络传输的方式进行存储。 阅读详情

相关推荐

[Unity存档系统]简单介绍Unity常见存档系统之一PlayerPrefs以及使用方法

学习目标: 如果你和我同样苦恼于游戏相关的数据怎么存储与读取,那么不妨看看这个up主有关Unity存档系统的教程。[Unity] 存档系统 Part 1 | PlayerPrefs | Unity初学者系列教程 | 数据存取 | 存档读档 | Save&Load_哔哩哔哩_bilibili在本视频中你将学到Unity引擎中三种常见的数据存储方式中的第一种:PlayerPrefs主要内容:什么是PlayerPrefs如何使用PlayerPrefsPlayerPrefs的优缺点以及适用范围构建一个.

dangoxiba的博客 9435

【Unity 笔记】PlayerPrefs 数据存储

开发平台:Unity 2019版本以上 编程平台:Visual Studio 2019 编程语言:C#   一、什么是PlayerPrefs? 描述:在游戏会话之间存储玩家偏好。   二、存储位置 Windows平台:HKCU\Software\[公司名称]\[产品名称]下注册表内 Linux平台:~/.config/unity3d/[公司名称]/[产品名称]下注册表内 Windows应用商店程序:%userprofile%\AppData\Local\Packages\[产品包 ID]>\Loca

Mr.River的博客 3263

深入了解Unity的PlayerPrefs类:一份详细的技术指南(五)

在Unity游戏开发中,PlayerPrefs类为我们提供了一种方便的方式来存储和检索读取玩家的数据,包括游戏设置,进度等。它是一种轻量级的,用于数据存储和检索的工具,允许我们在玩家的设备上存储少量的数据。存储的数据可以在应用程序的生命周期内,甚至在多次启动应用程序之间持久存在。

Mr.Y仙森的博客 9129

Unity存储小能手:PlayerPrefs指南

PlayerPrefs 是 Unity 提供的一个极其方便的工具,用于在设备本地快速、简单地存储少量的 int, float, string 类型数据。它非常适合保存用户设置、简单的游戏状态标记和非关键的本地得分。 然而,开发者必须清醒地认识到它的局限性:有限的数据类型、不适合大量数据、以及完全不安全的特性。明智地选择使用场景,避免用它存储敏感或关键数据,才能真正发挥其作为本地数据存储“利器”的作用。

ZeroBugX的博客 1834

Unity PlayerPrefs 之 PlayerPrefs数据存储读取

Unity Playerprefs 之 Playerprefs数据存储读取。  unity3d提供了一个用于本地持久化保存与读取的类——PlayerPrefs。工作原理非常简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值。本节介绍如何使用PlayerPrefs存储和读取数据,具体如下 一、基本概念 PlayerPrefs: Stores and access...

qq_38411133的博客 1260

Unity游戏数据存储方案全解析:从PlayerPrefs到健壮存档系统设计

在Unity游戏开发中,数据持久化是保障玩家体验和游戏完整性的核心技术。其核心原理是将游戏运行时状态通过序列化技术转化为可存储的格式,并在不同会话间可靠读取。这项技术的价值在于,它直接决定了游戏的稳定性、可维护性以及对抗数据丢失或作弊的能力。常见的应用场景包括保存玩家进度、存储游戏设置以及管理大量的静态配置数据。针对不同的需求,开发者需要选择合适的存储方案:对于简单的键值对偏好设置,可以使用Unity内置的PlayerPrefs,但其安全性低且功能有限;对于复杂的玩家存档和配置,JSON序列化因其良好的可读

372

Unity数据持久化之PlayerPrefs

数据持久化之PlayerPrefs

FAREWELL00075的博客 2657

Unity零基础到入门☀️| 万字教程 讲解Unity中的数据存储 PlayerPrefs、XML、JSON【建议收藏】

本文章是Unity零基础到入门专栏的系列文章。 适合对Unity3D引擎感兴趣的小伙伴学习,偏向于新手学习! 本篇文章就来介绍一下Unity中三种基本的数据存储方式:PlayerPrefs、XML、JSON

努力前行,总会成为自己心中的那道光 8万+

Unity实现游戏注册登录的功能(PlayerPrefs实现)

1.首先创建好注册登录需要的各个节点,在需要的输入框处添加UIInput脚本合Collider碰撞器(这里由NGUI实现) 2.了解下Unity的PlayerPrefs存储。 目前,在Unity3D中只支持int、string、float三种数据类型的读取,所以我们可以使用这三种数据类型来存储简单的数据。目前Unity3D中用于数据持久化的类为PlayerPrefs,如下: //保存数据 Play...

qq_43588531的博客 6196

Unity 数据存储☀️ |(六)PlayerPrefs解析

PlayerPrefs是Unity内置的一个静态类,可以用于存储一些简单的数据类型:int ,string ,float。可以用它来做成计分板这类需要可持续化存储的小地方。

m0_58523831的博客 1万+

【unity数据交互】-Unity公共类PlayerPrefs

Unity公共类PlayerPrefs的知识点和实践

秩沅 2061

Unity数据持久化之PlayerPrefs,详细

本博客主要记录PlayerPrefs的使用,本文比较啰嗦,比较长 1、什么是数据持久化 数据持久化就是将内存中的数据模型转化为存储模型,以及将存储模型转化为内存中数据模型的通称 简述:将游戏中的数据存储到硬盘,然后可以下次进游戏的时候读取硬盘中的数据到内存。 ...

D_R的博客 1万+

Unity 之 转微信小游戏本地数据存储方法分享

Unity转微信小游戏游戏数据存储问题分析和解决方案分享,

陈言必行 -- Unity游戏开发领域优质博主 1万+

如何在Unity中使用PlayerPrefs存储游戏进度

Unity中的PlayerPrefs允许我们在游戏中存储和访问玩家偏好设置,包括游戏进度。在本文中,我们将学习如何使用PlayerPrefs存储游戏进度,并提供完整的代码示例。

shguxudong11的博客 947

五子棋AI实战:极大极小搜索、Alpha-Beta剪枝与禁手实现

博弈树搜索是双人零和博弈AI的经典决策框架,其核心思想是假设对手最优应对,通过递归遍历走法空间寻找最优解。极大极小搜索配合Alpha-Beta剪枝,能在不影响决策结果的前提下将搜索量降至平方根级别,大幅提升搜索效率。在五子棋场景中,还需处理黑棋禁手规则,包括双三、双四和长连判定,并将其融入搜索框架。评估函数基于棋型识别对局面打分,走法排序和迭代加深进一步优化剪枝效果。这些技术共同构成了一个可运行的五子棋AI,适用于棋类AI入门与博弈搜索实践。

weixin_29054399的博客 131

Oracle EBS R12.2 安装 -- Step by Step

Oracle EBS R12.2 安装 -- Step by Step

Albert Tan DBA之路 1512

Unity数据存储方案全解析:从PlayerPrefs到SQLite的工程化选型指南

数据持久化是软件开发中的基础概念,指将程序运行时的数据状态保存到非易失性存储介质中,确保应用关闭后数据不丢失。其核心原理是通过序列化将内存中的对象转换为可存储的格式(如二进制、文本或数据库记录),再通过IO操作写入磁盘。这一技术对于保障用户体验和数据连续性至关重要,尤其在游戏开发领域,它直接关系到存档安全、配置管理和性能表现。在Unity引擎中,开发者常面临多种数据存储方案的选择,其中PlayerPrefs因其简单易用而被广泛认知,但它仅适用于存储极简的偏好设置。对于更复杂的应用场景,如需要管理大量静态配置

weixin_33937778的博客 391

Android 14安装的APK默认允许运行时权限

本文介绍了在Android系统中实现安装应用后自动授予运行时权限的方法。通过在安装完成广播中检测应用安装状态,调用新增的DefaultPermissionGrantPolicy.grantAppRuntimePermissions()函数来授予常规权限,并使用allowSpecialPermission()处理特殊权限(如安装未知应用和悬浮窗权限)。文章详细说明了如何修改DefaultPermissionGrantPolicy类,添加grantAppRuntimePermissions和grantRunti

热衷于Android Framework和系统APP的修改经验分享 683

Unity:PlayerPrefs笔记

写本系列的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解,方便自己以后快速复习,减少遗忘。

qq_65078669的博客 1183

「UG/NX」Block UI 曲线收集器CurveCollector

曲线收集器块用于选择一条或多条曲线,包括通过选择意图连接的末端曲线链。曲线选择意图用于此块,但它不支持“交点处停止”、“跟随圆角”、“中间链”和“特征内链”等规则选项。

何曾参静谧的博客 1090

评估篇| 大模型评测综述

1、基于人类的评测。与针对基础大语言模型的自动化评测不同,微调大语言模型的评测更加注重模型在实际应用场景中的表现,如与人类交互的自然度、对齐度等。2、基于模型的评测。例如,AlpacaEval 排行榜 基于由大语言模型合成的人类需求指令作为评测任务,然后收集待评估大模型的回应,并采用 GPT-4 等大语言模型作为评测员,将待评估大语言模型的输出与参考输出进行成对比较。1、大语言模型对评估设置极为敏感,包括问题的表述方式、提示样本的选择以及答案的解析策略等,这些细微的差别都可能导致评估结果的显著变化。

youbingchen的博客 637

Unity之数据持久化——PlayerPrefs

什么是数据持久化? 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内从中的数据模型的统称 即:游戏数据存储到硬盘,硬盘中的数据读取到游戏中 游戏运行时—(变量数据)—内存<——>硬盘 PlayerPref是Unity提供的可以用于存储读取玩家数据的公共类 1、存储相关 PlayerPrefs的数据存储类似于键值对存储,一个键对应一个值,提供了存储3中数据的方法:int,float,string 键:string类型 值:int,float,st.

Go_Accepted的博客 3473

使用蒙特卡洛模拟方法在MATLAB中估算居里温度: 一个详细而通俗的指南

居里温度是磁性材料失去磁性的温度。但是,计算机模拟为我们提供了一个在理论和实验之间的桥梁,使我们能够在不进行实际测量的情况下估计这一重要参数。在下一部分,我们将详细介绍蒙特卡洛迭代的核心代码,以及如何使用它来模拟磁性材料中原子的行为。在估算居里温度的上下文中,我们将使用蒙特卡洛方法来模拟磁性材料中的原子或分子的行为。通过使用蒙特卡洛方法,我们可以在MATLAB中估算居里温度,从而为理论研究和实验设计提供有价值的信息。:我们使用的是一个有限的尺寸的网格模型,这可能导致一些大小效应,特别是在接近居里温度时。

qq_38334677的博客 978

【PlayerPrefs】Unity学习笔记——数据持久化之PlayerPrefs的简单理解与应用

总结一下,我们在第一节学习了基础的PlayerPrefs知识,在第二节针对PlayerPrefs存储类型、安全性等方面的问题进行了小小的简单讨论,并写出一个较为通用的简单存读档工具

yumei_ww的博客 3434

论文必备 - YOLOv8训练前一键扩充数据集,支持9种扩充方法,支持图像和标签同步扩充

在网络模型训练前,大量的数据集是必备的。而对于一些特殊场景中的特殊目标,大量的数据集往往难以获取,无法满足模型训练的基本需求。本文提供了,脚本可一键运行,。

Limiiiing的博客 769

游戏开发:逻辑与渲染分离技术解析

游戏开发中逻辑与渲染分离的架构设计 本文系统阐述了游戏开发中逻辑与渲染分离的设计原则与实践方法。文章首先定义了核心概念:逻辑层负责游戏规则与状态,渲染层处理视觉表现,二者通过数据模型层进行通信。通过历史回顾,揭示了从早期混合架构到现代分层设计的演变过程。 在技术实现层面,文章详细分析了分离架构的优势:性能优化、流畅度控制、测试便利性、扩展灵活性以及团队协作效率。提供了Unity和Unreal两大引擎的具体实现方案,包括代码示例、分层模型和最佳实践。特别探讨了网络同步、客户端预测、插值处理等关键技术难点。 文

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1060
上一篇: MySQL 8.0 vs 5.6实战避坑指南:从性能优化到安全配置的全面对比
下一篇: 如何在RK3588开发板上部署YOLOv5模型?从训练到推理的完整流程(附避坑指南)
linux6sysadmin
博客等级 码龄4年 59粉丝 1615原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值