Unity 游戏存档之XML实现

——尊重原创,转载请注明出处,谢谢!
http://blog.csdn.net/d/article/details/52551247

这篇文章已经是我写的XML和JSON应用系列的第三篇了,有了前面两篇的基础。这篇文章读起来应该不是很困难。当然如果你是直接看的这篇文章吃力的话可以先去看看前面两篇文章。

这篇文章主要讲述如何使用对游戏进行存档。

1.所需脚本:( 工程Scripts/Save文件夹下的所有脚本 )
DataBase,DataItem,GameData,GameDataManager,XmlSave


2.脚本简介:
DataBase : 信息基类,存储欲存档的信息。对于各种存档信息可以由此派生。派生类一般不含方法。 DataItem : 信息项基类,操作信息类。为Manager提供所有DataBse。 GameData : 游戏信息,所有需要存档的DataBase都需要存储在改类List中。 GameDataManager : 游戏存档类,提供Save()和Load()接口。实质就是将该类的gamedata对象序列化保存。 XmlSave : Xml序列化类。


3.使用方法:
这里我用我写的一个小游戏作为Demo讲解如何使用以上脚本对游戏进行存档。 游戏内容是你控制一个Player在迷宫的入口通过WSAD移动,你需要找到迷宫的出口。游戏界面左上方有记录你已经用过的时间,右上角显示的是历史最快通关时间。空格键可以切换第一人称和第三人称视角,J键可以对游戏进行存档,K键可以对游戏进行读档。


  • 首先,我们应该分析这个游戏的存档应该保存哪些信息?

我们需要保存的是Player的Transform信息,当然如果游戏中不会有影响Player的Scale参数的可以不保存大小。还有呢?我们还需要将存档时候的时间保存下来。历史通关时间呢?不需要,为什么呢?类似于历史通关实际这类的存储它不取决于用户存档的因素,换句话说不管用户什么时候存档,或者存不存档。这个值也不会变。所以我们将这个属性单独存储。

  • 然后,我们对需要存储的信息分下类:

比如Player的信息是Player自己管理,而当前时间则是由TimeControl管理或者式GameControl来管理。所以根据以上,我们把需要存储的数据分成两个类。

  • 接着,根据我们上面的分类来分别派生各自的Data类:

PlayerData : 继承DataBase,包含Player需要存档的属性,即坐标,旋转,大小。
PlayerDataItem :继承DataItem, 主要负责存档时将属性放入PlayerData,读档时利用PlayerData对Player设置属性。
TimeData : 继承DataBase,存储当前消耗时间信息。
TimeDataItem : 继承DataItem,主要负责存档时将属性放入TimeData,读档时利用TimeData对显示时间Label设置。

  • 最后,在DataBase中添加上你所有的派生类。如下:
using System.Xml.Serialization;

//在这里添加你的所有需要序列化的信息类

[XmlInclude(typeof(PlayerData))]
[XmlInclude(typeof(TimeData))]
public class DataBase {

    public string objName;

}


4.代码展现:

PlayerData & PlayerDataItem :

using UnityEngine;
using System.Collections;
using System.Xml.Serialization;

public class PlayerData : DataBase
{

    public Vector3 playerPos;
    public Vector3 playerEul;
    public Vector3 playerSca;
    public float playerSpeed;

}
public class PlayerDataItem : DataItem {

    private PlayerController playerCtrl = null;
    public PlayerDataItem()
    {
        item = new PlayerData();
    }

    public override void Start()
    {
        base.Start();
        playerCtrl = GetComponent<PlayerController>();
    }
    //设置Player属性
    public override void Load(DataBase data)
    {
        transform.localPosition = ((PlayerData)data).playerPos;
        transform.localEulerAngles = ((PlayerData)data).playerEul;
        transform.localScale = ((PlayerData)data).playerSca;
        playerCtrl.walkSpeed = ((PlayerData)data).playerSpeed;
    }
    //存储Player属性
    public override void Save()
    {
        ((PlayerData)item).playerPos = transform.localPosition;
        ((PlayerData)item).playerEul = transform.localEulerAngles;
        ((PlayerData)item).playerSca = transform.localScale;
        ((PlayerData)item).playerSpeed = playerCtrl.walkSpeed;
    }
}

TimeData & TimeDataItem :

using UnityEngine;
using System.Collections;

public class TimeData :DataBase
{
    public float time;
}

public class TimeDataItem : DataItem {

    private TimeControl timeCtrl;
    public TimeDataItem()
    {
        item = new TimeData();
    }
    public override void Start()
    {
        base.Start();
        timeCtrl = GetComponent<TimeControl>();

    }
    //设置时间
    public override void Load(DataBase data)
    {
        timeCtrl.Timer = ((TimeData)data).time;
    }
    //存储时间
    public override void Save()
    {
        ((TimeData)item).time = timeCtrl.Timer;
    }
}

最后就是调用的逻辑代码了:

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
using LitJson;


public class TestData : MonoBehaviour {
    //这里式加载场景的两种方式。和本篇文章所讲内容无关。
    void Start()
    {
        //LoadScene.LoadSenceXML();
        LoadScene.LoadSenceJSON();
    }


    void Update () {
        if(Input.GetKeyDown(KeyCode.J))
        {
            GameDataManager._instance.Save();
        }
        if(Input.GetKeyDown(KeyCode.K))
        {
            //加载存档
            GameDataManager._instance.Load();
            List<DataBase> datas = GameDataManager._instance.cloneData.datas;
            //并用存档信息去初始化所有存档了的物体
            for(int i = 0 ; i < datas.Count ; i ++)
            {
                //注意要保存信息的物体名字不能重复
                GameObject go = GameObject.Find(datas[i].objName);
                go.GetComponent<DataItem>().Load(datas[i]);

            }
        }
    }
}

注意上面最后一条注释,因为我们是用GameObject.Name作为key区别的,所以要保证所有要存档物体的名字不能一样。当然这也可以通过重新编码使得解除这个限制。我这里给出一个方案,就是在DataBase中添加int id.然后在所属的DataItem注册的时候让GameData返回一个唯一的Key。这样就可以用这个Key去区别所有对象了。

以上就是存档的全部内容了,如果你有更好的方案或者代码,文章有什么错误请在下面评论区提出来。本人致以万分的感谢!!


Demo源码地址:点这里
  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值