【问题标题】:C# Bytes array and Saved GamesC# 字节数组和保存的游戏
【发布时间】:2015-12-07 10:28:37
【问题描述】:

我需要一点帮助。我在 Unity3D 中制作了一个足够简单的游戏,我想使用 SavedGames(谷歌游戏服务)保存一些变量(黄金、库存等)。 我已经阅读过它,显然我必须将数据作为字节数组发送到 Google Games。所以我也读过字节数组,但我不明白。每一篇关于它的文章或问题似乎都假设对它有一定程度的了解(我显然没有)。我被困住了。 我的问题是:你如何从 int 变量到字节数组?

例如: 用户有 52 个金币 (int gold_coins)、三个治疗药水 (int heal_pot) 和 4 个法力药水 (int mana_pot)。我想将这三个变量放入一个字节数组中,当用户保存游戏状态时,我可以将其发送到 Google。然后,当他再次加载它时,字节数组中的数据需要返回到整数。 (当我首先看到如何将它们放入数组时,我可能会自己弄清楚最后一部分)。

我希望你们能向我解释或指出正确的方向。与此同时,祝您有个愉快的星期一。谢谢。

编辑 2:所以,我有这个:

在 SaveData.cs 中:

using UnityEngine;
using ProtoBuf;

[ProtoContract]
public enum DataType{
    pu0 = 0; //gold in game
    pu1 = 1; //heal_pot ingame
    pu2 = 2; //mana_pot ingame
}

[ProtoContract]
public class PBSaveData{
    [ProtoMember(1)]
    public DataType type;
    [ProtoMember(2)]
    public int amountStored;
}

在 PBGameState.cs 中:

using ProtoBuf;

[ProtoContract]
public class PBGameState{
    [ProtoMember(1)]
    public PBSaveData[] saveData;
}

在 SaveManager.cs 中:

using ProtoBuf;
using System.IO;

public class SaveManager{
    private string gameStateFilePath;

    void SaveState(){
        PBStateGame state = new PBGameState();
        state.saveData = new PBSaveData[3];
        for (int i=0; i<state.saveData.Length{
            state.saveData[i] = new PBSaveData();
            state.saveData[i].type = "pu" + (i+1);
            state.saveData[i].amoundStore = its[i] //its is where is store my inventory locally.
        }
        using(var ms = new MemoryStream()){
        // Serialize the data to the stream
            Serializer.Serialize(ms, state);
            byteArray = ms.ToArray();
        }
        // Create a texture the size of the screen, RGB24 format
        int width = Screen.width;
        int height = Screen.height;
        Texture2D Screenshot = new Texture2D( width, height, TextureFormat.RGB24, false );
        // Read screen contents into the texture
        Screenshot.ReadPixels( new Rect(0, 0, width, height), 0, 0 );
        Screenshot.Apply();


        long TotalPlayedTime = 20000;
        string currentSaveName =  "sg";
        string description  = "Modified data at: " + System.DateTime.Now.ToString("MM/dd/yyyy H:mm:ss");


        GooglePlaySavedGamesManager.ActionGameSaveResult += ActionGameSaveResult;
        GooglePlaySavedGamesManager.instance.CreateNewSnapshot(currentSaveName, description, Screenshot, byteArray, TotalPlayedTime);
    }
}

void LoadState()
{
    PBGameState state = new PBGameState ();

    using(var ms = new MemoryStream(byteArray)){
        state = Serializer.Deserialize<PBGameState> (ms);
        AndroidMessage.Create ("loadtest", state.saveData[0].amountStored.ToString());
    }

    if (state.saveData != null) {
        // Iterate through the loaded game state 
        for (int i = 0; i < state.saveData.Length; i++) {
            its [i] = state.saveData [i].amountStored;
        }
    } else {
        AndroidMessage.Create ("loadtest", "notworking");
    }
}

所以保存显然有效,但是当我重新启动游戏时,似乎没有加载数据(我有一个开始加载过程的按钮)并且库存是空的...... 知道我做错了什么吗?谢谢你:)

这是教程的链接: tuto

有人吗?

【问题讨论】:

  • 将你的东西序列化为字符串并将其转换为字节[]。 Byte[] 只不过是字节数组(8 位整数)。
  • 看一个好的序列化库,比如Protobuf-net github.com/mgravell/protobuf-net

标签: c# unity3d bytearray


【解决方案1】:

你需要做的是:

  • 有一个对象来存储您要保存的值,例如类名GameState 或其他任何内容
  • 序列化你的这个类的实例,这是在你的字节数组中转换你的实例的过程
  • 当你想从字节数组中取回你的值时,你需要反序列化你的字节数组

例如见Convert any object to a byte[]

另见https://msdn.microsoft.com/en-us/library/ms233843.aspx


回答第二个问题:

不要使用FileStream,而是使用MemoryStream

// New MemoryStream, used just like any other stream, but without file (all in memory)
var ms = new MemoryStream();

// Serialize the data to the stream
Serializer.Serialize(fs, state);

// Get back the byte array from the stream
// Doesn't matter where the Position is on the stream, this'll return the
// whole MemoryStream as a byte array
var byteArray = ms.ToArray();

【讨论】:

  • 但请注意,对链接问题的公认答案推荐 BinaryFormatter,它仅适用于临时存储和通信/远程处理,而不适用于持久存储。使用 BF 进行长期存储总是以泪水告终。使用 ContractSerializer 或 Protocol 缓冲区或类似的持久性。
  • 链接的答案是序列化的一个基本示例,它显示了一般过程是如何工作的。也就是说,正如您所指出的,例如 protobuf 的版本容错性更高,这是在处理持久存储时需要考虑的因素。
  • 谢谢两位。在我阅读 protobuf-net 之前,这行得通吗:
  • 我已将 OP 重新编辑到我所在的位置:使用 protobug-net 设置(我认为)
  • 它有效,我明天将用代码编辑 OP,以便它可以帮助其他人。非常感谢。
【解决方案2】:

首先,将变量保存为某种特定格式的字符串(例如用分号分隔)。然后,使用某种编码将其转换为 byte[]。

string saveState = String.Format("{0};{1};{2}", gold_coins, heal_pot, mana_pot);
byte[] saveBytes = Encoding.UTF8.GetBytes(saveState);

之后,您可以使用 byte[] 为所欲为。解析保存的数据:

string[] retrievedData = Encoding.UTF8.GetString(saveBytes).Split(';'); //saveBytes is the Byte[] you get from the cloud.
int gold = int.Parse(retrievedData[0]);

解析后的数组将按照您在字符串中的顺序包含项目。

但是这只是一种简单的(完全不推荐)序列化方式)。如需更好的方法,请参阅 @ken2k 的回答。

【讨论】:

  • 谢谢,那我试试ken2k的回答:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-10
  • 1970-01-01
  • 1970-01-01
  • 2015-02-18
  • 2021-08-30
相关资源
最近更新 更多