简体   繁体   English

C#:如何在Unity中使用数组而不是列表重写用于管理游戏数据序列化的代码?

[英]C#: How can I rewrite my code for managing Game Data Serialization using an Array instead of a List in Unity?

I am fairly new to coding and I am currently working on creating scripts to serialize data to a hard drive. 我是编码的新手,目前正在创建脚本以将数据序列化到硬盘。 I have managed to get it working with a list with the type "Game". 我设法使其与类型为“游戏”的列表一起使用。 The Game class holds data that can be serialized. Game类保存可以序列化的数据。 I have been trying to write this code to work with an array instead that has a size of 3. Unfortunately, I have been having trouble when I run my program and try to use my GUI. 我一直在尝试编写此代码以使用大小为3的数组来代替。不幸的是,在运行程序并尝试使用GUI时遇到了麻烦。 I just need a push in the right direction for how to approach rewriting my code. 我只需要在正确的方向上推动如何重写我的代码。 I know to start with: 我知道从开始:

public static Game[] savedGames = new Game[3];

But how do I get my definitions to work with using an array instead of a list. 但是,如何使用数组而不是列表来使用定义。

//<SaveLoad.cs>

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

public static class SaveLoad {
    // Note: [ 07 / 20 / 2018]
    // 1. Make  an array of game saves index of 3. (To replace list) 
    // 2. Create definition for overwritesave()??
    // 3. Rewrite definitions Save/Load/Delete to work with an array
    // 4. Start working on custom GUI

public static List<Game> savedGames = new List<Game>(3);

public static void Save()
{
    savedGames.Add(Game.current);
    BinaryFormatter bf = new BinaryFormatter();
    FileStream file = File.Create(Application.persistentDataPath + 
    "/savedGames.gd");
    Debug.Log("The file is saved at " + Application.persistentDataPath);
    bf.Serialize(file, savedGames);
    file.Close();
}

public static void Load()
{
    if (File.Exists(Application.persistentDataPath + "/savedGames.gd"))
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath + 
        "/savedGames.gd", FileMode.Open);
        Debug.Log("The File is loaded from " + 
        Application.persistentDataPath);
        savedGames = (List<Game>)bf.Deserialize(file);
        file.Close();
    }
}

public static void DeleteSave(int index) {

    if (File.Exists(Application.persistentDataPath + "/savedGames.gd"))
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath + 
        "/savedGames.gd", FileMode.Open);
        savedGames = (List<Game>)bf.Deserialize(file);
        file.Close();
    }

    savedGames.RemoveAt(index); 
    // Removes element in List from the passed Index

    BinaryFormatter bf2 = new BinaryFormatter();
    FileStream file2 = File.Create(Application.persistentDataPath + 
    "/savedGames.gd"); //you can call it anything you want
    Debug.Log("Save file has been Updated at " + 
    Application.persistentDataPath);
    bf2.Serialize(file2, savedGames); // Saves Changes to Data
    file2.Close();
    }
 }

This is my script for the GUI. 这是我的GUI脚本。 I currently have it working for a list but I am having trouble using it with an array as well. 我目前在列表中使用它,但是在将其与数组一起使用时也遇到了麻烦。 I need help finding a way to pass an index value from the menu to modify an array. 我需要帮助,找到一种从菜单传递索引值来修改数组的方法。

//<MainMenu.cs>

 using UnityEngine;
 using System;
 using UnityEngine.SceneManagement;

 public class MainMenu : MonoBehaviour {

 int index = 0;

 public enum Menu {
    MainMenu,
    NewGame,
    Continue,
    delete,
    caution
}

 public Menu currentMenu;

     void OnGUI () {

         GUILayout.BeginArea(new Rect(0,0,Screen.width, Screen.height));
         GUILayout.BeginHorizontal();
         GUILayout.FlexibleSpace();
         GUILayout.BeginVertical();
         GUILayout.FlexibleSpace();

        if(currentMenu == Menu.MainMenu) {

            GUILayout.Box("THE EIGHT");
            GUILayout.Space(10);

        if(GUILayout.Button("New Game")) {
            Game.current = new Game();
            currentMenu = Menu.NewGame;
        }

        if(GUILayout.Button("Continue")) {
            SaveLoad.Load();
            currentMenu = Menu.Continue;
        }

        if(GUILayout.Button("Delete Save")) {
            SaveLoad.Load();
            currentMenu = Menu.delete;
        }

        if(GUILayout.Button("Quit")) {
            Application.Quit();
        }
    }

    else if (currentMenu == Menu.NewGame) {

        GUILayout.Box("Name Your Characters");
        GUILayout.Space(10);

        GUILayout.Label("Some Strange Boy");
        Game.current.Nestor.name = 
        GUILayout.TextField(Game.current.Nestor.name, 20);
        GUILayout.Label("Some Strange Girl");
        Game.current.SomeGirl.name = 
        GUILayout.TextField(Game.current.SomeGirl.name, 20);
        GUILayout.Label("Some Strange Friend");
        Game.current.SomeBro.name = 
        GUILayout.TextField(Game.current.SomeBro.name, 20);

        if(GUILayout.Button("Save")) {
            //Save the current Game as a new saved Game
            SaveLoad.Save();
            //Move on to game...
            SceneManager.LoadScene(2);
        }

        GUILayout.Space(10);
        if(GUILayout.Button("Cancel")) {
            currentMenu = Menu.MainMenu;
        }

    }

    else if (currentMenu == Menu.Continue) {

        GUILayout.Box("Select Save");
        GUILayout.Space(10);

        foreach(Game g in SaveLoad.savedGames) {
            if(GUILayout.Button(g.Nestor.name + " - " + g.SomeGirl.name + " - " + g.SomeBro.name)) {
                Game.current = g;
                //Move on to game...
                SceneManager.LoadScene(2);
            }

        }

        GUILayout.Space(10);
        if(GUILayout.Button("Cancel")) {
            currentMenu = Menu.MainMenu;
        }

    }

    else if (currentMenu == Menu.delete)
    {

        GUILayout.Box("Select Save to Delete");
        GUILayout.Space(10);

        foreach (Game g in SaveLoad.savedGames)
        {
            if (GUILayout.Button(g.Nestor.name + " - " + g.SomeGirl.name + " 
            - " + g.SomeBro.name))
            {
                index = SaveLoad.savedGames.IndexOf(g);
                Debug.Log(index);
                currentMenu = Menu.caution;
            }

        }

        GUILayout.Space(10);
        if (GUILayout.Button("Cancel"))
        {
            currentMenu = Menu.MainMenu;
        }

    }
else if(currentMenu == Menu.caution) {

        GUILayout.Box("Are you sure?");
        GUILayout.Space(10);
        if (GUILayout.Button("Yes")) {
            Debug.Log(index);
            SaveLoad.DeleteSave(index);
            currentMenu = Menu.MainMenu;
        }

           GUILayout.Space(10);
            if (GUILayout.Button("No")) {
                currentMenu = Menu.delete;
            }

        }

        GUILayout.FlexibleSpace();
        GUILayout.EndVertical();
        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();
        GUILayout.EndArea();

    }
}

You pretty much only need to replace your cast of a List<Game> to a Game[] . 您几乎只需要将List<Game>演员List<Game>替换为Game[] Here's some (error unhandled) sample code infrastructure to get you started. 这是一些(未处理错误)示例代码基础结构,可帮助您入门。 As a hint, wrapping your file/serialization code in try , catch with IOException and SerializationException should take care of the brunt of normal user case scenarios. 提示一下,将文件/序列化代码包装在try使用IOExceptionSerializationException catch应该可以避免普通用户案例场景的冲击。 It may be worth trying to mess with your .bin files just to see what happens and test various corner case functionality of your code. 可能只想弄清楚.bin文件,看看会发生什么并测试代码的各种特殊情况,这是值得的。

void Awake() {
    //this is an object initializer, pass your Game[] in place of this
    Save(new[] {
        new Game { propertyStub = 0 },
        new Game { propertyStub = 1 },
        new Game { propertyStub = 2 }
    });

    var gA = Load();
    if(gA == null || gA.Length > 3) throw new SerializationException("Serialize error");

    foreach (var g in gA) Debug.Log(g);
}

public static void Save(Game[] gA) {
    using (var f = File.Create(Directory.GetCurrentDirectory() + "\\sample.bin")) new BinaryFormatter().Serialize(f, gA);
}

public static Game[] Load() {
    using (var f = File.Open(Directory.GetCurrentDirectory() + "\\sample.bin", FileMode.Open)) return (new BinaryFormatter().Deserialize(f)) as Game[];
}

//Stub class used for testing purposes
[Serializable]
class Game {
    public int propertyStub { get; set; }

    public override string ToString() {
        return "propertyStub value: " + propertyStub;
    }
}

In addition, it's worth mentioning that the .net Binary serializer is pretty slow in comparison to other common serialization methods in general usage cases, so I advise against using it in your final builds. 另外,值得一提的是, .net Binary序列化程序在一般情况下与其他常见序列化方法相比非常慢 ,因此,建议不要在最终版本中使用它。 Other well-known serialization methods like XML and JSON generate very human readable output, and works well when you don't care about final file size, or serialization speed. 其他众所周知的序列化方法(如XMLJSON)会生成易于阅读的输出,并且在您不关心最终文件大小或序列化速度时也能很好地工作。 If you really want speed and size, the Google Protocol Buffers (Protobuf) are a good starting point. 如果您确实想要速度和大小,则Google协议缓冲区(Protobuf)是一个很好的起点。

All of the links I've given you contain boiler-plate copy and paste code, although they all end up serializing dynamic array lists. 我给您的所有链接都包含样板代码复制和粘贴代码,尽管它们最终都会序列化动态数组列表。 As I said above, simply changing the explicit casts to arrays should not cause you any headache. 就像我在上面说的,简单地将显式强制转换为数组不会引起任何麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM