使用序列化 存档 物品位置信息

      最近公司需要去做存档功能,因为需要存档物品位置信息所以我在网上开始找资料,其中遇到几个坑在这里记录一下,防止以后碰到同样的错误以及给阅读过的读者少绕点路。

  本来是想用json直接储存的,但是因为要和同事统一,所以选择使用序列化储存,对于声音以及设定上简单信息的存档我们可以使用PlayerPrefs就可以做到。

   首先将变量序列化

    [SerializeField]
    public Slider SoundSlider;
    [SerializeField]
    public Toggle SoundToggle;

然后在我们使用自带的方法检索键值获取存档以及,传值来改变状态或者数值。具体代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SoundContrl : MonoBehaviour {
    [SerializeField]
    public Slider SoundSlider;
    [SerializeField]
    public Toggle SoundToggle;

    //工程名
    public string ProName = "";

    private AudioSource audioSource;

    /// <summary>
    /// 声音初始化
    /// </summary>
    private void Awake()
    {
        //获取AudioSource
        audioSource = transform.GetComponent<AudioSource>();

        //检索音乐键值
        if (!PlayerPrefs.HasKey(ProName + "MusicOn"))
        {
            //初始化音乐设置
            PlayerPrefs.SetFloat(ProName + "MusicOn", 0.5f);
            SoundToggle.isOn = true;
            SoundSlider.value = 0.5f;
            PlayerPrefs.Save();
        }
        else
        {
            //这里我设置声音为0的时候音乐关闭
            if (PlayerPrefs.GetFloat(ProName + "MusicOn") == 0)
            {
                SoundToggle.isOn = false;
            }
            else
            {
                SoundToggle.isOn = true;
                //储存音乐大小
                SoundSlider.value = PlayerPrefs.GetFloat(ProName + "MusicOn");
            }
        }
    }

	
	// Update is called once per frame
	void Update () 
	{
        //声音随着按钮事件更新
        audioSource.volume = SoundSlider.value;
        audioSource.enabled = SoundToggle.isOn;
        SoundSave();
    }

    /// <summary>
    /// 声音存档更新
    /// </summary>
    private void SoundSave()
    {

        if (!SoundToggle.isOn)
        {
            PlayerPrefs.SetFloat(ProName+"MusicOn", 0);
        }
        else
        {
            PlayerPrefs.SetFloat(ProName+"MusicOn", SoundSlider.value);
        }
    }
}

参考链接:https://blog.csdn.net/kmyhy/article/details/78643293

这个是unity自带的存档没有什么难度,困扰我的是序列化。根据上面参考链接我开始学习使用序列化。但是有个问题,这个案例的序列化使用的int类型,当我使用vector3类型或者Gameobject类型都会报错提示不支持序列化,但是我主要储存的坐标不是固定的一个点。于是我开始翻阅资料,发现序列化只支持简单类型比如int,float,string类型的序列化,那我该怎么办呢,找了半天总算让我找到能够让我这个大脑转不过弯的菜鸟的资料。

https://www.cnblogs.com/madinglin/p/8490721.html

上面的资料是作者使用json来对游戏对象存储读取位置信息数据,既然不能储存vector3类型那我就直接储存坐标x,y,z的数值不行就行了吗?加载Gameobject类型我也可以用名字代替,然后resource方法加载出来。这里就扯远了,但是我们的确可以通过这种方式达到我们的要求。

我们先创建一个save类,来储存位置信息。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Save
{
    //建筑坐标
    public string PosX;
    public string PosY;
    public string PosZ;

    //
    public Save() { }
    public Save(string x, string y, string z)
    {
        PosX = x; PosY = y; PosZ = z;
    }
    public override string ToString()
    {
        return string.Format("x ={0}   y ={1}   z = {2}", PosX, PosY, PosZ);
    }
    
}

然后我们开始写保存的方法

public void SaveGame()
    {
        // 创建 save对象

        BuildList.Clear();

        foreach (Transform item in Targets.transform)
        {
            Vector3 Pos = item.transform.position;
            Save save = new Save(Pos.x.ToString(), Pos.y.ToString(), Pos.z.ToString());
            BuildList.Add(save);
        }
        
        // 创建文件保存save对象
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.dataPath + "/GameSave.Scene");
        bf.Serialize(file, BuildList);
       
        file.Close();

        BuildList.Clear();
        //  TODO 数据重置

        Debug.Log("Game Saved");
    }

因为我需要保存的物体坐标不是只有一个,所以我需要遍历我需要保存的物体的所有坐标,然后将这些信息都保存在集合里,然后创建文件和流数据保存集合信息。

接下来开始是载入,中间出了一个小插曲,因为我是直接复制黏贴代码,结果中间还是报错了,因为我传入的是集合并不是save类型所以抄代码理所当然就报错了,然后我该用什么类型呢?想到这里我蒙蔽了我也不知道啊,就在我以为需要使用封包拆包进行分析的时候看到了这个资料https://blog.csdn.net/e295166319/article/details/52790131

序列化什么类型,反序列化什么类型!序列化的是集合类型,那么能反序列化的也就只能是集合类型(JOJO立)。

public void LoadGame()
    {
        BuildList.Clear();
        if (File.Exists(Application.dataPath + "/GameSave.Scene"))
        {
            //1 重置场景
            ResetBuild();

            //2 加载保存数据
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.dataPath + "/GameSave.Scene", FileMode.Open);
            BuildList = bf.Deserialize(file)as List<Save>;

            file.Close();

            //3 载入建筑
            for (int i = 0; i < BuildList.Count; i++)
            {
                Vector3 Pos = new Vector3(float.Parse(BuildList[i].PosX), float.Parse(BuildList[i].PosY), float.Parse(BuildList[i].PosZ));
                CreatBuild(PrefabObj, Pos);
            }


        }
        else
        {
            Debug.Log("No game saved!");
        }
    }

完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public class Game : MonoBehaviour {
    //建筑生成点
    [SerializeField]
    public Transform Targets;
    //生成建筑
    public GameObject PrefabObj;
    //保存列表
    private List<Save> BuildList;

    
    public void SaveGame()
    {
        // 创建 save对象

        BuildList.Clear();

        foreach (Transform item in Targets.transform)
        {
            Vector3 Pos = item.transform.position;
            Save save = new Save(Pos.x.ToString(), Pos.y.ToString(), Pos.z.ToString());
            BuildList.Add(save);
        }
        
        // 创建文件保存save对象
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.dataPath + "/GameSave.Scene");
        bf.Serialize(file, BuildList);
       
        file.Close();

        BuildList.Clear();
        //  TODO 数据重置

        Debug.Log("Game Saved");
    }

    public void LoadGame()
    {
        BuildList.Clear();
        if (File.Exists(Application.dataPath + "/GameSave.Scene"))
        {
            //1 重置场景
            ResetBuild();

            //2 加载保存数据
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.dataPath + "/GameSave.Scene", FileMode.Open);
            BuildList = bf.Deserialize(file)as List<Save>;

            file.Close();

            //3 载入建筑
            for (int i = 0; i < BuildList.Count; i++)
            {
                Vector3 Pos = new Vector3(float.Parse(BuildList[i].PosX), float.Parse(BuildList[i].PosY), float.Parse(BuildList[i].PosZ));
                CreatBuild(PrefabObj, Pos);
            }


        }
        else
        {
            Debug.Log("No game saved!");
        }
    }

    /// <summary>
    /// 实例化建筑
    /// </summary>
    /// <param name="build">要实例化的物体</param>
    /// <param name="Pos">实例化坐标</param>
    public void CreatBuild(GameObject build,Vector3 Pos)
    {
        Vector3 TargetPostion = new Vector3(Pos.x, Pos.y, Pos.z);
        GameObject Prefab = Instantiate(build) as GameObject;
        Prefab.transform.position = TargetPostion;
        Prefab.transform.parent = Targets.transform;

        Prefab.transform.GetComponent<SelectBuild>().SelectShow(false);
    }

    /// <summary>
    /// 重置建筑
    /// </summary>
    private void ResetBuild()
    {
        BuildList.Clear();
        foreach (Transform item in Targets.transform)
        {
            Destroy(item.gameObject);
        }
    }

    // Use this for initialization
    void Awake () 
	{
        BuildList = new List<Save>();

    }
	
	
}

这样一来就没有问题了,程序员的思维和基础真的非常重要,身为码农以后的路还长着继续加油。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值