Unity3D(C#)手游如何实现关卡保存与加载功能?
Unity C# 关卡进度保存与加载实现方案
方案选型
根据你的需求复杂度,可以选两种常用的实现方式:
- 仅需存储已解锁最大关卡、最近游玩关卡ID这类简单数据:直接用Unity原生
PlayerPrefs即可,无需处理文件读写逻辑,跨平台适配已经由Unity封装完成 - 需存储每个关卡的星级、收集物、通关时长等复杂维度数据:使用JSON序列化+本地文件存储的方案,扩展性更强
具体实现步骤
1. 基于PlayerPrefs的轻量实现
适合需求简单的中小体量游戏,代码量极小:
保存逻辑
调用时机:关卡完成进入下一关、游戏退出/切后台时
public void SaveLevelProgress(int clearedLevelId, int currentPlayedLevelId) { // 存储已解锁的最大关卡ID,比如通关关卡3则解锁关卡4 PlayerPrefs.SetInt("UnlockedMaxLevel", clearedLevelId + 1); // 存储最近游玩的关卡ID,下次启动游戏可以直接跳转 PlayerPrefs.SetInt("LatestPlayedLevel", currentPlayedLevelId); // 立即写入磁盘,避免游戏异常崩溃导致存档丢失 PlayerPrefs.Save(); }
加载逻辑
调用时机:游戏启动、进入关卡选择界面时
public (int unlockedMaxLevel, int latestPlayedLevel) LoadLevelProgress() { // 第二个参数为默认值,无存档时默认解锁第一关 int unlockedMaxLevel = PlayerPrefs.GetInt("UnlockedMaxLevel", 1); int latestPlayedLevel = PlayerPrefs.GetInt("LatestPlayedLevel", 1); return (unlockedMaxLevel, latestPlayedLevel); }
自动触发保存配置
- 关卡结算界面点击「下一关」按钮时,直接调用
SaveLevelProgress传入对应关卡ID即可 - 游戏退出/切后台的自动保存,可以挂载到MonoBehaviour的
OnApplicationQuit、OnApplicationPause生命周期函数中,避免切后台被系统杀进程导致进度丢失
2. 基于JSON序列化的复杂进度实现
适合需要存储多维度关卡数据的项目,可自由扩展字段:
第一步:定义序列化数据结构
using System; using System.Collections.Generic; // 总关卡进度数据 [Serializable] public class LevelProgressData { public int unlockedMaxLevel; public int latestPlayedLevel; // Key为关卡ID,Value为对应关卡的详细数据 public Dictionary<int, SingleLevelInfo> levelInfoMap; } // 单个关卡的详细数据 [Serializable] public class SingleLevelInfo { public bool isCleared; // 星级评分1-3星 public int starCount; // 关卡内收集的道具数量 public int collectedItemCount; // 最短通关时长 public float fastestClearTime; }
第二步:实现存读盘管理器
using System.IO; using UnityEngine; public class LevelSaveManager : MonoBehaviour { public static LevelSaveManager Instance; private string saveFilePath; private void Awake() { Instance = this; // persistentDataPath为Unity跨平台可写目录,不会被系统随意清理 saveFilePath = Path.Combine(Application.persistentDataPath, "LevelProgress.dat"); } // 保存进度 public void SaveProgress(LevelProgressData data) { string jsonContent = JsonUtility.ToJson(data); // 可选:对JSON做简单异或加密,防止用户直接修改本地存档 File.WriteAllText(saveFilePath, jsonContent); } // 加载进度 public LevelProgressData LoadProgress() { if (!File.Exists(saveFilePath)) { // 无存档时返回初始化的新存档 return new LevelProgressData() { unlockedMaxLevel = 1, latestPlayedLevel = 1, levelInfoMap = new Dictionary<int, SingleLevelInfo>() }; } string jsonContent = File.ReadAllText(saveFilePath); // 对应加密逻辑的解密步骤 return JsonUtility.FromJson<LevelProgressData>(jsonContent); } // 退出游戏自动存盘 private void OnApplicationQuit() { // 传入当前内存中的进度数据即可 // SaveProgress(currentRuntimeProgress); } // 切后台自动存盘 private void OnApplicationPause(bool isPause) { if (isPause) { // SaveProgress(currentRuntimeProgress); } } }
注意事项
PlayerPrefs仅适合存轻量数据,不要存储大量复杂结构,且本身是明文存储,不要放敏感内容- 不要把存档存在
Application.dataPath路径下,项目打包后该路径为只读,会导致存盘失败 - 避免游戏运行过程中频繁调用存盘接口,仅在关卡结算、退出、切后台三个节点调用即可,减少性能损耗
- 对存档安全性要求高的项目,可以给存档内容加上MD5校验位,加载时先校验内容是否被篡改
内容的提问来源于stack exchange,提问作者Mehar Muzammal
相关产品推荐
相关产品推荐

