4.PlayerPrefs基础知识总结

4.总结


4.1 知识点

学习的主要内容

优点

缺点

主要用处


4.2 核心要点速览

PlayerPrefs 能干什么

  • Unity 提供的静态工具类,用来按「键—值」读写玩家侧偏好数据(音量、新手引导标记、简单进度等)。
  • 值类型被引擎限制在三种:intfloatstring;键一律是字符串。
  • 需要存 bool、枚举、向量等,只能自己约定编码(例如 bool0/1 写入 SetInt)。

存储模型与常见坑

  • 语义上就是键值对:一个 key 对应一个槽位;后写入覆盖先写入,与这次用的是 SetInt 还是 SetFloat 无关
  • 若对同一 keySetIntSetFloat,再用 GetInt 去读,读到的往往不是旧整数,而是该类型的默认值(文中示例为 0)。线上排障时,优先怀疑「键复用 + 类型混写」。
  • 其它类型只能「降精度 / 升精度」再塞进这三种里,例如把布尔折成整数。

写入、内存与落盘

  • Set* 先把改动放在内存里的偏好缓存中,不保证立刻落到磁盘
  • 正常退出游戏时,Unity 会自动刷盘;进程崩溃、强杀时,未落盘改动可能丢失。
  • 需要「改完马上落盘」(例如付费结果、关键进度),在合适的逻辑点调用 PlayerPrefs.Save()

读取语义

  • 只要在本进程里 Set 过,即使还没 Save同一运行会话内 Get 也能拿到刚写入的值。
  • GetInt / GetFloat / GetString 的重载:只传 key 时,找不到键会返回类型默认值(int0float0fstring"");传第二参数时,找不到键则返回你给的默认值,适合做「首次启动初始化」。
  • HasKey 用来判断某个键是否存在;不是用来替代默认值的——没有键时直接 Get 带默认参数往往更简单。文中强调它解决的是「有没有写过这个键」这类问题。

核心 API

分类 API 作用 默认 / 注意
SetInt / SetFloat / SetString 按 key 写入值 同 key 后写覆盖;类型混用再读会踩坑
刷盘 Save 把当前改动写入磁盘 崩溃前未 Save 可能丢;性能上不要每帧狂刷
GetInt / GetFloat / GetString 按键取值 单参版用类型默认;双参版用自定义默认
HasKey 键是否存在 不等价于业务「空值判断」
DeleteKey 删单个键
DeleteAll 清空本应用偏好 慎用,调试外一般封装权限

各平台数据落在哪

平台 存放位置(文中表述) 怎么理解
Windows 注册表 HKCU\Software\[公司名]\[产品名] 公司名 / 产品名来自 Player 设置;编辑器下常见路径会经 Unity\UnityEditor\... 再落到项目配置的名字
Android /data/data/包名/shared_prefs/ 下的 xml 与包名绑定;真机调试需要知悉权限与路径习惯
iOS /Library/Preferences/[应用ID].plist 随应用沙盒走

键名设计与集合数据

  • 不同语义的数据禁止共用一个 key,否则就是互相覆盖、静默丢数据。
  • 多角色、多存档槽、多条排行榜记录,习惯用「前缀 + 业务字段后缀」拆键,例如 player1_namerankScore0
  • List:先写 Count,再按索引循环写每一项的字段;读的时候按 Count 重建列表。练习里的玩家装备、排行榜条目都是这个套路。

4.3 面试题精选

基础题

1. PlayerPrefs 能直接存哪些类型

题目

PlayerPrefs 原生支持写入哪些 C# 类型?如果想存布尔值,一般怎么做?

深入解析

正文明确:只有 intfloatstring 三种写入接口。键始终是 string

布尔在业务里通常映射为 0/1(或 SetInt("flag", value ? 1 : 0)),读出来再还原。枚举可以强转成整数存。复杂结构不能一行 API 搞定,要自己设计编码或换存储方案。

答题示例

原生就三种:intfloatstring,键是字符串。

布尔一般用 01SetInt,读的时候再转成 bool

参考文章
  • 2.基本方法

2. 只 Set 不 Save,当前运行里能不能读到

题目

调用 SetInt 后没有调用 PlayerPrefs.Save(),立刻 GetInt 能否拿到刚写的值?什么时候可能丢?

深入解析

文中结论:同一运行进程内,Set 后即使未 SaveGet 也能读到。持久化到磁盘发生在 Save 被调用或正常退出等时机;若进程异常结束,未落盘的改动可能丢失。

答题示例

能读到,因为改动先在内存偏好里,Get 读的是当前会话状态。

真正写到磁盘要靠 Save 或正常退出;崩溃、强杀时没落盘就可能丢,关键数据要显式 Save

参考文章
  • 2.基本方法

3. 同一 key 混用 SetInt 与 SetFloat 会怎样

题目

PlayerPrefs.SetInt("k", 18),再 PlayerPrefs.SetFloat("k", 20.2f),接着 GetInt("k") 得到什么?说明原因。

深入解析

同一 key 只有一个槽位,后写入覆盖前写入。最终槽位里是按浮点写入的,再用 GetInt 去读时,与文中示例一致,会得到 int 的默认值 0(而不是 18 或 20 的整数部分这种「想当然」)。这题考的是「键唯一 + 类型匹配」意识。

答题示例

会得到 int 的默认值 0,因为同一个 key 被后面的 SetFloat 占掉了,再用 GetInt 读,类型对不上那条记录的预期,表现成默认。

线上要避免同一 key 混用不同类型,团队内约定命名和读写封装。

参考文章
  • 2.基本方法

进阶题

1. 什么时候必须考虑显式调用 Save

题目

既然退出时会自动写盘,为什么示例里仍在 Save() 方法末尾调用 PlayerPrefs.Save()?什么场景下你倾向于手动刷盘?

深入解析

自动刷盘依赖「正常退出」这条路径;崩溃、断电、移动端被系统杀进程时,内存里的偏好可能来不及写回。练习代码在存档方法末尾 Save,是在「玩家点保存、过关结算」这类关键节点强制落盘,降低丢失概率。工程上还要权衡频率:每帧 Save 会引入 I/O 压力,一般只在关键点调用。

答题示例

正常退出 Unity 会帮你写,但崩溃或强杀就不保险。

所以在存档、购买结果、重要进度变更后显式 Save,把风险压住;不要在高频逻辑里每帧刷。

参考文章
  • 2.基本方法

2. Windows 上 PlayerPrefs 大致存在哪

题目

在 Windows 上,PlayerPrefs 数据主要落在什么系统机制里?路径里的公司名和产品名从哪来?

深入解析

正文给出注册表路径模板 HKCU\Software\[公司名称]\[产品名称],名称来自 Player 设置。编辑器下调试时,文中步骤经过 Unity\UnityEditor\... 再找到对应公司 / 产品节点。能答出「注册表 + 与 Player 配置绑定」即可;不要求背诵每一级子键在不同 Unity 版本上的细微差别。

答题示例

主要在注册表当前用户下,Software 里按公司名、产品名分层。

名字是项目在 Player 设置里配的那两个字段;调设置、清存档时常要去注册表或等价存储里找对节点。

参考文章
  • 3.不同平台的存储位置

3. HasKey 和带默认值的 Get 怎么分工

题目

什么时候用 HasKey,什么时候直接用 GetXxx(key, defaultValue) 就够了?

深入解析

文中强调:HasKey 判断「这个键有没有被写过」;Get 的第二参数负责「没有键时给业务默认值」。若逻辑是「从未存档过则用一套初始数值」,双参 Get 往往一次搞定。若你要区分「老玩家升级存档」和「全新安装」这类分支,HasKey 才有额外信息量。

答题示例

Get 带默认值适合绝大多数初始化:没有键就用默认。

HasKey 用在需要区分「是否存在过这条记录」的分支,不是用来替代默认值判空的。

参考文章
  • 2.基本方法

深度题

1. 用 PlayerPrefs 做大型存档的主要短板

题目

练习里用 Count + 索引后缀 去模拟列表、排行榜;从工程角度,长期把大块、多变的游戏数据都塞进 PlayerPrefs,主要风险和成本是什么?

深入解析

系列正文只讲了 API、键唯一和「拆成多条键」的写法,没有规定何时必须换存储方案。结合这些前提能归纳:键会随列表变长而变多,改结构或删条目容易留下旧键;数据一复杂,读写逻辑分散,不如集中式存档易维护。面试里常再追问「那用什么替代」——JSON、二进制、SQLite 等是常见答案,但具体选型要看项目规模与平台,别把具体容量、加密细节说成 Unity 文档原文。

答题示例

PlayerPrefs 适合键值偏好和小块数据;列表要手写 count 和循环键,结构一变就要改键规则,还容易留下废弃键。

数据一大、结构一复杂,维护成本和踩键冲突风险都上去,一般会换成更集中的存档方案,而不是继续堆键。

参考文章
  • 2.基本方法
  • 3.不同平台的存储位置

2. 键名冲突的成因与规避

题目

文中说「同一项目里 key 相同会造成数据丢失」。多模块、多程序员协作时,你会怎么约定键名,避免互相覆盖?

深入解析

正文只给原则:唯一性由 key 决定,相同 key 即覆盖。工程上常见做法:模块前缀(Audio_Quest_)、版本或存档槽后缀、集中常量类维护键字符串,禁止魔法字符串散落在各处。练习里 keyName + "_name" 也是前缀隔离思路的雏形。

答题示例

冲突根因是 PlayerPrefs 全局一个命名空间,后写覆盖先写。

用模块前缀、存档槽、常量类统一管 key,禁止各处硬编码同一短字符串;多角色就像练习里用 Player1_Player2_ 这类前缀隔开。

参考文章
  • 2.基本方法
  • 3.不同平台的存储位置


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏