我想在Minecraft之类的场景中保存对象

时间:2019-02-17 10:30:31

标签: c# unity3d minecraft

在Minecraft中,保存了很多块的位置。

我将通过使用PlayerPrefs以自己的方式尝试。

int i, ObjectType;
Vector3 Pos;

// ObjectType is a block ID such as grass block or iron block in Minecraft.
// Pos is a position of each blocks

PlayerPrefs.SetString("object" + i, ObjectType + ", " + Pos); 

但是,在处理数百个数据时,据说不建议使用PlayerPrefs。我只知道将数据保存在PlayerPrefs中。

在这种情况下我该怎么办?

2 个答案:

答案 0 :(得分:2)

PlayerPref旨在存储和访问游戏会话(如设置)之间的玩家偏好。您只能使用它来保存字符串,整数或浮点数据类型。是的,不应将其用于存储所需的大量数据。如果您决定添加更多级别怎么办?最后,您将在一个PlayerPrefs词典对象中获得所有级别,设置和其他游戏信息,该对象很难维护,效率低下并且易于用户修改。

您应该使用有关级别,块对象列表等的信息来制作类/结构,然后将对象序列化为二进制文件,然后可以将其作为文件保存在本地设备中,或流式传输到在线服务器。我建议观看这个Unity Live Session教程:Persistence - Saving and Loading Data(对于初学者)。

您还可以将游戏数据本地或在线存储在数据库中。

答案 1 :(得分:1)

我建议您使用例如XML文件来存储数据的所有结构

:用于存储一个块的数据。您可以根据需要扩展它,例如使用BlockType枚举或材料颜色等(任何可序列化的东西)

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

[Serializable]
public class Block
{
    [XmlAttribute] public string Name;
    [XmlElement] public Vector3 Position;

    // for the serializer a parameter-free default constructor is mandatory
    public Block() { }

    public Block(string name, Vector3 position)
    {
        Name = name;
        Position = position;
    }
}

BlocksData :用于存储所有块的数据并处理XML文件IO

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

[XmlRoot("BlocksData")]
[Serializable]
public class BlocksData
{
    [XmlArray]
    [XmlArrayItem]
    public List<Block> Blocks = new List<Block>();

    public void Save(string filePath)
    {
        var serializer = new XmlSerializer(typeof(BlocksData));
        using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
        {
            serializer.Serialize(stream, this);
        }
    }

    public static BlocksData Load(string filePath)
    {
        if (!File.Exists(filePath))
        {
            Debug.LogWarning("File not found: " + filePath);
        }

        var serializer = new XmlSerializer(typeof(BlocksData));
        using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            return serializer.Deserialize(stream) as BlocksData;
        }
    }
}

最后是一个控制器类,它使用此BlocksData并对其进行处理。例如

using System.Collections.Generic;
using System.IO;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

public class BlocksController : MonoBehaviour
{
    private const string FILE_EXTENSION = ".xml";

    // fileName of the XML file (without extension)
    public string FileName;

    // prefab to be spawned for each block
    public GameObject BlockPrefab;

    // blocks in the scene
    public List<Transform> SceneBlocks;

    // blocks in the data
    public BlocksData BlocksData;

    private static string Folder
    {
        get
        {
#if UNITY_EDITOR
            return Application.streamingAssetsPath;
#else
            return Application.persistentDataPath;
#endif
        }
    }

    private string FilePath
    {
        get
        {
            return Path.Combine(Folder, FileName + FILE_EXTENSION);

        }
    }

    [ContextMenu("Load Blocks")]
    public void LoadBlocks()
    {
        // Load from file
        BlocksData = BlocksData.Load(FilePath);

        // remove current scene blocks
        foreach (var sceneBlock in SceneBlocks)
        {
            // Have to se destroyImmediate in editmode
            if (Application.isEditor && !Application.isPlaying)
            {
                DestroyImmediate(sceneBlock.gameObject);
            }
            else
            {
                Destroy(sceneBlock.gameObject);
            }
        }

        // instantiate and setup prefab foreach block in data
        foreach (var block in BlocksData.Blocks)
        {
            var newBlock = Instantiate(BlockPrefab, block.Position, Quaternion.identity, transform);
            newBlock.name = block.Name;

            // don't forget to add it to the list of sceneBlocks
            SceneBlocks.Add(newBlock.transform);
        }
    }

    [ContextMenu("Save Blocks")]
    public void SaveBlocks()
    {
        // clear current data list
        BlocksData.Blocks.Clear();

        // add a block data foreach block in scene
        foreach (var sceneBlock in SceneBlocks)
        {
            BlocksData.Blocks.Add(new Block(sceneBlock.name, sceneBlock.position));
        }

        // finally write to file
        BlocksData.Save(FilePath);

#if UNITY_EDITOR
        AssetDatabase.Refresh();
#endif
    }
}

有关更多详细信息,请参见Saving and Loading Data: XmlSerializer