Unity游戏中如何将游戏设置保存到文件中而不返回序列化错误?

问题描述 投票:0回答:1

我正在制作一款安卓游戏,选项菜单提供了3个不同的设置:背景音乐音量、音效音量、屏幕侧射击按钮的位置。还有高分应该保存。

我试着根据某人提供的答案创建了一个脚本,但当我用音乐音量滑块测试时,它一直在返回关于事物不可序列化的错误。一开始它说 "SerializationException: Type 'GameData' in Assembly 'Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable",所以我试着按照某个地方的建议在类代码上方添加"[System.Serializable]",但现在它却返回错误 "SerializationException: Type 'UnityEngine.MonoBehaviour' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable"。

另外,在序列化错误之后,它还写了错误 "IOException: 路径C:\Users\UserName\AppData\LocalLow\CompanyName\AppName\save.dat上存在共享违规"。

这是代码。

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

[System.Serializable]
public class GameData : MonoBehaviour
{
    public int highScore = 0;
    public float musicVol = 1;
    public float sfxVol = 1;
    public int shootSide = 1;
    // Start is called before the first frame update
    private void Start()
    {
        LoadFile();
    }
    public void HighScoreValue(int highS)
    {
        highScore = highS;
        SaveData();
    }
    public void MusicValue(float musicV)
    {
        musicVol = musicV;
        SaveData();
    }
    public void SfxValue(float sfxV)
    {
        sfxVol = sfxV;
        SaveData();
    }
    public void ShootSideValue(int shootS)
    {
        shootSide = shootS;
        SaveData();
    }
    private void SaveData()
    {
        string destination = Application.persistentDataPath + "/save.dat";
        FileStream file;

        if (File.Exists(destination))
        {
            file = File.OpenWrite(destination);
        }
        else
        {
            file = File.Create(destination);
        }
        GameData data = gameObject.AddComponent<GameData>();
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(file, data);
        file.Close();
    }
    private void LoadFile()
    {
        string destination = Application.persistentDataPath + "/save.dat";
        FileStream file;

        if (File.Exists(destination))
        {
            file = File.OpenRead(destination);
        }
        else
        {
            Debug.Log("File not found");
            return;
        }
        BinaryFormatter formatter = new BinaryFormatter();
        GameData data = (GameData)formatter.Deserialize(file);
        file.Close();
        highScore = data.highScore;
        musicVol = data.musicVol;
        sfxVol = data.sfxVol;
        shootSide = data.shootSide;
    }
}

代码中有什么问题?先谢谢你了。

c# unity3d
1个回答
1
投票

MonoBehaviour 可能无法实例化使用 new 关键字,这是解串器所需要的。您的附加 AddComponentGetComponent 不需要,因为这个脚本已经 的组件,您想在 GameObject.


你应该(至少我会)将可序列化类型分离成一个纯数据类结构,并在实现逻辑的MonoBehaviour中使用它的一个实例。

可以像这样

[Serializable]
public class GameDataContainer
{
    public int highScore = 0;
    public float musicVol = 1;
    public float sfxVol = 1;
    public int shootSide = 1;
}

public class GameData : MonoBehaviour
{
    // since this is a serialized, 
    // it will be initialized with a valid instance by default
    public GameDataContainer data;

    // NEVER use +"/" for system paths!
    // initilaize this only once
    private string destination => Path.Combine(Application.persistentDataPath, "save.dat");

    // Start is called before the first frame update
    private void Start()
    {
        LoadFile();
    }

    public void HighScoreValue(int highS)
    {
        data.highScore = highS;
        SaveData();
    }

    public void MusicValue(float musicV)
    {
        data.musicVol = musicV;
        SaveData();
    }

    public void SfxValue(float sfxV)
    {
        data.sfxVol = sfxV;
        SaveData();
    }

    public void ShootSideValue(int shootS)
    {
        data.shootSide = shootS;
        SaveData();
    }

    private void SaveData()
    {
        using (var file = File.Open(destination, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(file, data);
        }
    }

    private void LoadFile()
    {
        if (!File.Exists(destination))
        {
            Debug.Log("File not found");
            return;
        }

        using(var file = File.Open(destination, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            var formatter = new BinaryFormatter();
            data = (GameDataContainer)formatter.Deserialize(file);
        }
    }
}

0
投票

由于你的 GameData 类继承自Unity的 MonoBehaviour,序列化将需要 MonoBehaviour 也是可序列化的;但似乎不是。

也许这将会有所帮助。序列化&反序列化Unity3D MonoBehaviour脚本。

© www.soinside.com 2019 - 2024. All rights reserved.