进行 存储路径 新的 del jpg cati spa 全局变量 .net
前言
前段时间完成了自己的小游戏Konster的制作,今天重新又看了下代码。原先对关卡解锁数据的存储时用了Unity自带的PlayerPref(字典式存储数据)。
读取关卡数据的代码:
- void Awake ()
- {
- foreach(Transform Child in transform) //Update Level Lists
- {
- //Get Level‘s Name
- string levelname = Child.name.Substring(0,1);
- //Load level data ,check if it is unlocked
- if(PlayerPrefs.GetInt(levelname) == 0) //Set Lock
- {
- Child.GetChild(1).gameObject.SetActive(true);
- }
- else
- {
- Child.GetChild(1).gameObject.SetActive(false);
- }
- }
- }
某一关通关时,解锁下一关:
- public void LevelCompleted() // level completed
- {
- int temp = thisLevel + 1; //next level
- string nextLevel = temp.ToString();
- if (PlayerPrefs.GetInt(nextLevel) == 0) // check if next level is locked
- PlayerPrefs.SetInt(nextLevel, 1);
- PlayerPrefs.Save();
- StartCoroutine(GameSuccess()); //Show the GameSuccess UI
- }
个人觉得虽然使用起来方便,但是如果我想存取一些对象结构数据的话很麻烦,于是自己试着写了个简单的对象数据存储。
使用JSON存储数据
什么是Json
JSON是一种轻量级的数据交换格式。它的本质其实就是一种对象以键值为基础保存的字符串。
比如有一个Person类:
- public class Person
- {
- public string name;
- public int age;
- public Person(string _name,int _age)
- {
- // constructor
- name = _name;
- age = _age;
- }
- }
- //
- static void Main()
- {
- Person kk = new Person("KK",20);
- }
然后实例化一个叫KK的人,那么它的JSON字符串格式为:{"name": "KK","age":"19"}。
应用:利用JSON对关卡数据进行存储
这里使用的是JsonFx,一个基于.NET的JSON操作库。下载地址1(CSDN) 下载地址2(GitHub)
首先我们需要确定下数据的存储路径,这里定义了一个FilePath类来存放所有路径(全局变量)。
- public class FilePath{
- public static readonly string GAMEDATA_PATH = Application.dataPath + "/GameData"; //游戏数据的文件夹
- public static readonly string LEVEL_PATH = GAMEDATA_PATH + "/leveldata.txt"; //关卡解锁数据存储路径
- //之后有新的数据需要存储路径时可以拓展
- }
然后将JSON操作和文件IO操作简单封装一下:
- using JsonFx.Json;
- using System.IO;
- public class DataManager{
- //保存对象数据
- public static void SaveClass<T>(T saveClass,string path)
- {
- //如果游戏数据文件夹不存在,创建一个文件夹
- if(!Directory.Exists(FilePath.GAMEDATA_PATH))
- Directory.CreateDirectory(FilePath.GAMEDATA_PATH);
- File.WriteAllText(path, JsonWriter.Serialize(saveClass));
- }
- //读取对象数据
- public static T LoadClass<T>(string path)
- {
- string list = File.ReadAllText(path);
- return JsonReader.Deserialize<T>(list);
- }
- }
然后定义一个Level类保存单个关卡数据,需要特别注意的是,JSON序列化的对象必须显式地指明默认构造函数,不然JsonFx会报错。
- public class Level{
- //关卡编号
- public int LevelNumber { get; set; }
- //关卡是否解锁
- public bool IsUnlocked { get; set; }
- public Level(){} //必须提供默认构造函数
- public Level(int _levelnumber,bool _IsUnlocked)
- {
- LevelNumber = _levelnumber;
- IsUnlocked = _IsUnlocked;
- }
- }
再定义一个LevelList来存储所有的关卡。
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class LevelLists {
- public List < Level > lists;
- //默认构造函数,用于json序列化与反序列化
- public LevelLists() {}
- /// <summary>
- /// 赋值构造函数,用于游戏第一次启动的初始化
- /// </summary>
- public LevelLists(int levels) {
- lists = new List < Level > ();
- lists.Add(new Level(1, true)); //关卡1肯定必须提前解锁的
- for (int i = 2; i <= levels; i++) {
- lists.Add(new Level(i, false)); //其余关卡锁定
- }
- }
- }
然后为了在游戏第一次启动时初始化数据,我们需要一个脚本FirstLaunch来检测游戏是否是第一次启动。在场景里创建一个空物体挂上这个脚本即可。
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class FirstLaunch: MonoBehaviour {
- public int InitLevelNum; //初始化的关卡数,在编辑器的Inspector里填写好,我填写的是4关
- void Awake() {
- Check();
- }
- void Check() //检查游戏是否是第一次启动
- {
- int IsFirstLaunch = PlayerPrefs.GetInt("First"); //获取这个键对应的值,不存在默认为0
- if (IsFirstLaunch == 0) {
- //如果不存在,创建并把值设置为1
- PlayerPrefs.SetInt("First", 1);
- PlayerPrefs.Save();
- InitializeLevelLists();
- }
- }
- void InitializeLevelLists() //在本地初始化关卡列表的数据
- {
- LevelLists mylist = new LevelLists(InitLevelNum);
- DataManager.SaveClass < LevelLists > (mylist, FilePath.LEVEL_PATH);
- }
- }
然后对于关卡列表,我们写一个脚本来管理它的状态
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- public class LevelsControll : MonoBehaviour{
- public GameObject[] Levels; //关卡选择
- public GameObject[] Locks; //关卡锁
- // Use this for initialization
- void Start()
- {
- Initialize();
- }
- void Initialize() //关卡列表初始化
- {
- //读取关卡数据
- LevelLists data = DataManager.LoadClass<LevelLists>(FilePath.LEVEL_PATH);
- for(int i = 0; i < Levels.Length;i++)
- {
- //初始化点击事件监听
- ClickListener.Get(Levels[i]).onClick += SelectLevels;
- //初始化关卡解锁状态
- Locks[i].SetActive(!data.lists[i].IsUnlocked);
- }
- }
- public void SelectLevels(GameObject go)
- {
- int i = 0;
- for(;i < Levels.Length;i++)
- {
- if (go == Levels[i])
- break;
- }
- //Load Level 这里为了测试直接打印了
- Debug.Log("Load level " + (i + 1));
- }
- }
由于关卡选择直接用的UGUI的Image组件,它没有UI点击事件处理,但我们可以自己写一个脚本实现Unity的点击事件接口IPointerClickHandler来监听点击事件。
- using UnityEngine;
- using UnityEngine.EventSystems;
- public class ClickListener : MonoBehaviour, IPointerClickHandler //注意这是Unity提供的点击接口
- {
- public delegate void VoidDelegate(GameObject go); //事件委托
- public VoidDelegate onClick;
- public static ClickListener Get(GameObject go) //获取对应GameObject的Listener脚本,没有就新增一个
- {
- ClickListener listener = go.GetComponent<ClickListener>();
- if (listener == null)
- listener = go.AddComponent<ClickListener>();
- return listener;
- }
- public void OnPointerClick(PointerEventData eventData)
- {
- if (onClick != null)
- onClick(gameObject);
- }
- }
OK,然后在场景中弄好UI,挂上脚本,点击运行。
可以发现创建了一个叫GameData的文件夹,然后该文件夹下新建了一个leveldata.txt文件,里面存储了关卡的数据。
停止运行,然后这里我再在文本文件里把第四关的IsUnlocked属性修改为true,再运行,发现第四关解锁了。
由此,一个简单的关卡数据存储也就完成了。
当然这样没有什么安全性,玩家只需要在对应文件夹里修改这个文本文件就能解锁了,因此有些时候我们需要对数据进行加密。关于数据加密又是另一个话题了( ̄▽ ̄)。
参考资料
《Unity5.X开发指南》 作者:罗盛誊
Unity3D学习(二):使用JSON进行对象数据的存储读取
来源: http://www.bubuko.com/infodetail-2320581.html