当前位置: 首页 > article >正文

Unity3D仿星露谷物语开发55之保存游戏到文件

1、目标

将游戏保存到文件,并从文件中加载游戏。

Player在游戏中种植的Crop,我们希望保存到文件中,当游戏重新加载时Crop的GridProperty数据仍然存在。这次主要实现保存地面属性(GridProperties)信息。

我们要做的是实现一个我们可以点击的方式,将游戏保存到一个文件中,然后点击加载按钮,它将获取该文件,然后将数据带回游戏中。

2、创建GameSave.cs脚本

在Assets/Scripts/SaveSystem下创建新的脚本命名为:GameSave.cs。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[System.Serializable]
public class GameSave
{// string key - GUID gameobject IDpublic Dictionary<string, GameObjectSave> gameObjectData;public GameSave(){gameObjectData = new Dictionary<string, GameObjectSave>();}
}

3、修改ISaveable.cs脚本

添加2行代码:

    GameObjectSave ISaveableSave();void ISaveableLoad(GameSave gameSave);

ISaveableSave: 保存变量和游戏对象,这一步是获取数据,后续会写入文件

ISaveableLoad:将游戏保存数据对象(从文件中读取的数据)作为它的参数

4、修改GridPropertiesManager.cs脚本

添加新的引用:

using UnityEngine.SceneManagement;

添加ISaveableLoad函数实现:

public void ISaveableLoad(GameSave gameSave)
{if(gameSave.gameObjectData.TryGetValue(ISaveableUniqueID, out GameObjectSave gameObjectSave)){GameObjectSave = gameObjectSave;// Restore data for current sceneISaveableRestoreScene(SceneManager.GetActiveScene().name);}
}

其中,ISaveableUniqueID是通过GetComponent<GenerateGUID>().GUID生成的。

在GenerateGUID的实现中,它的属性是[ExecuteAlways],即运行/编译时都会执行,实际上是需要编译时生成_gUID信息。_gUID是[SerializeField]属性,而[SerializeField] 标记的字段会被 Unity 自动序列化到场景文件或预制体中。

所以一个游戏中,GenerateGUID的值是不会变化的。

另外,GameObjectSave是属性变量,其定义为:

    public GameObjectSave GameObjectSave { get { return _gameObjectSave; } set { _gameObjectSave = value; } }
 

添加ISaveableSave方法的实现:

 public GameObjectSave ISaveableSave(){// Store current scene dataISaveableStoreScene(SceneManager.GetActiveScene().name);return GameObjectSave;}

5、修改SceneItemsManager.cs脚本 

 添加新的引用:

using UnityEngine.SceneManagement;

添加如下2个方法的实现:

 public void ISaveableLoad(GameSave gameSave){if(gameSave.gameObjectData.TryGetValue(ISaveableUniqueID, out GameObjectSave gameObjectSave)){GameObjectSave = gameObjectSave;// Restore data for current sceneISaveableRestoreScene(SceneManager.GetActiveScene().name);}}public GameObjectSave ISaveableSave(){// Store current scene dataISaveableStoreScene(SceneManager.GetActiveScene().name);return GameObjectSave;}

6、修改SaveLoadManager.cs脚本

SaveLoadManager有2个方法:StoreCurrentSceneData / RestoreCurrentSceneData。

在SceneControllerManager中,当场景切换和Start中会使用RestoreCurrentSceneData方法。

接下来就是改造SaveLoadManager,从文件中读写信息。

添加2个引用:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

接着添加2个函数:

public void LoadDataFromFile()
{BinaryFormatter bf = new BinaryFormatter();if(File.Exists(Application.persistentDataPath + "/WildHopeCreek.data")){gameSave = new GameSave();FileStream file = File.Open(Application.persistentDataPath + "/WildHopeCreek.data", FileMode.Open);gameSave = (GameSave)bf.Deserialize(file);  // loop through all ISaveable obvjects and apply save datafor(int i = iSaveableObjectList.Count - 1; i > -1; i--){if (gameSave.gameObjectData.ContainsKey(iSaveableObjectList[i].ISaveableUniqueID)){iSaveableObjectList[i].ISaveableLoad(gameSave);}else{// else if iSaveableObject unique ID is not in the game object data then destroy objectComponent component = (Component)iSaveableObjectList[i];Destroy(component.gameObject);}}file.Close();}UIManager.Instance.DisablePauseMenu();
}public void SaveDataToFile()
{gameSave = new GameSave();// loop through all ISaveable objects and generate save dataforeach(ISaveable iSaveableObject in iSaveableObjectList){gameSave.gameObjectData.Add(iSaveableObject.ISaveableUniqueID, iSaveableObject.ISaveableSave());}BinaryFormatter bf = new BinaryFormatter();FileStream file = File.Open(Application.persistentDataPath + "/WildHopeCreek.data" , FileMode.Create);bf.Serialize(file, gameSave);file.Close();UIManager.Instance.DisablePauseMenu();
}

可以通过如下代码查看存储的路径:

Debug.Log("dataPath:" + Application.persistentDataPath);

我的地址是:C:\Users\benbe\AppData\LocalLow\DefaultCompany\XingluValley

7、编辑UI界面

(1)设置界面元素

将PauseMenuPanel下的Tab2修改为Tab2SaveGame,

将SelectionTabButtonsPanel -> SelectionButton(2) -> Text的输入改为"Save/Load"。

给Tab2SaveGame对象添加Vertical Layout Group组件,相关配置如下:

在Tab2SaveGame下右击 -> UI -> Button(TextMeshPro),命名为SavevGameButton。再创建一个同样的Button命名为LoadGameButton。

分别点击SaveGameButton及LoadGameButton两个对象,修改Button属性的Normal Color为87775D  ,Highlighed Color为D8DB84   。

最后界面呈现的样式为:

(2)添加点击事件

SaveGameButton对应的点击事件:

LoadGameButton对应的点击事件:

8、运行游戏

运行游戏,收集地面上的item,并且种植了Crop,点击Esc -> Save Game。

退出游戏后重新进入,点击Esc -> Load Game。之前地面上已经被收集掉的item没有再次出现,Crop仍然保持之前的状态。

http://www.lryc.cn/news/2391772.html

相关文章:

  • 【无标题】C++23新特性:支持打印volatile指针
  • 【第4章 图像与视频】4.2 图像的缩放
  • 针对C语言的开发工具推荐及分析(涵盖编辑器、集成开发环境(IDE)、编译器、调试工具及辅助工具)
  • 在 WSL Ubuntu-24.04 上安装 Nacos 2.5.1 并使用 MySQL 数据库
  • 敏捷开发中如何避免迭代失控
  • Python基础 | jupyter工具的安装与基本使用
  • Python开发AI智能体(九)———构建RAG对话应用
  • NW907NW918美光固态闪存NW920NW930
  • 【Deepseek 学网络互联】跨节点通信global 和节点内通信CLAN保序
  • Python 迭代器:从基础到高级
  • 9.5 Q1 | 北京协和医学院GBD发文 | 1990-2021 年全球、区域和国家心力衰竭负担及其根本原因
  • 软件工程 3.0:智能驱动的软件新时代
  • 从C++编程入手设计模式1——单例模式
  • 根据Cortex-M3(包括STM32F1)权威指南讲解MCU内存架构与如何查看编译器生成的地址具体位置
  • vue的h函数(在 Vue 2中也称为 createElement)理解
  • MCP入门实战(极简案例)
  • STM32中,如何理解看门狗
  • Cursor从入门到精通实战指南(一):开始使用Cursor
  • 麒麟v10+信创x86处理器离线搭建k8s集群完整过程
  • 计算机组成原理——cache
  • EasyExcel使用导出模版后设置 CellStyle失效问题解决
  • 关于AWESOME-DIGITAL-HUMAN的部署
  • WebAssembly 及 HTML Streaming:重塑前端性能与用户体验
  • python同步mysql数据
  • shell之通配符及正则表达式,grep参数
  • RuoYi前后端分离框架集成手机短信验证码(一)之后端篇
  • Knife4j框架的使用
  • 深兰科技陈海波率队考察南京,加速AI医诊大模型区域落地应用
  • 【芯片设计中的交通网络革命:Crossbar与NoC架构的博弈C架构的博弈】
  • deepseek告诉您http与https有何区别?