Сохранить и загрузить инвентарь - PullRequest
1 голос
/ 26 июня 2019

Я уже создал инвентарь, и все работает отлично.Теперь я должен реализовать сохранение и загрузку инвентаря (в файле).Тем не менее, я застрял на том, как поступить.Я думал о создании сценария данных инвентаризации, чтобы получить сериализуемые данные и затем сохранить их.Я не использую объект сценариев.Не могли бы вы дать мне совет?Ниже приведен инвентарный код.

 public class Inventory2 : MonoBehaviour
 {
     public bool inventoryEnabled;
     public GameObject inventory, slotHolder;
     private Transform[] slot;
     public int level;

     void Start()
     {
         level = SceneManager.GetActiveScene().buildIndex;
         GetAllSlots();        
     }   

     void Update()
     {
         if (Input.GetAxis("Inventory") != 0)
         {
             inventoryEnabled = !inventoryEnabled;
         }

         if(inventoryEnabled)
         {
             inventory.SetActive(true);
         }
         else
         {
             inventory.SetActive(false);
         }
     }

     public void OnTriggerEnter(Collider other)
     {
         if (other.tag == "Clues")
         {            
             AddClue(other.GetComponent<Clue2>());            
         }
     }
     public void AddClue(Clue2 clue)
     {
         Text description = clue.GetComponent<Text>();

         for (int i = 0; i < 2; i++)
         {
             if(slot[i].GetComponent<Slot2>().empty == true && clue.pickedUp == false)
             {
                 slot[i].GetComponent<Slot2>().clue = clue;
                 slot[i].GetComponent<Slot2>().descriptionFinal = description;
                 slot[i].GetComponent<Slot2>().empty = false;
                 clue.GetComponent<Clue2>().pickedUp = true;
             }
         }
     }

     public void GetAllSlots()
     {
         slot = new Transform[Clue2.objects];

         for(int i = 0; i < Clue2.objects; i++)
         {
             slot[i] = slotHolder.transform.GetChild(i);
             slot[i].GetComponent<Slot2>().empty = true;
         }
     }
 }
 public class Slot2 : MonoBehaviour
 {
     public Clue2 clue;
     public bool empty;
     public Text descriptionFirst, descriptionFinal;

     void Awake()
     {

     }

     void Update()
     {
         if (clue)
         {
             this.GetComponentInChildren<Text>().text = descriptionFinal.text;
         }
         else
         {
             this.GetComponentInChildren<Text>().text = descriptionFirst.text;
             empty = true;
         }
     }
 }
 public class Clue2 : MonoBehaviour
 {
     public static int objects = 0;
     public static int objectsCollected = 0;
     public Text description;
     public bool pickedUp;

     public GameObject cluePopUpPanel, canvasCluesPanel;
     public Canvas canvasHUD;
     public static bool activeClue = false;

     void Awake()
     {
         objects++;
     }

     void Update()
     {
         if (canvasCluesPanel.gameObject.activeSelf == true && Input.GetAxis("PickUp") != 0)
         {
             activeClue = true;
             cluePopUpPanel.gameObject.GetComponent<UnityEngine.UI.Text>().text = description.text;
         }
     }

     private void OnTriggerEnter(Collider other)
     {
         if (other.tag == "Player")
         {
             if (canvasCluesPanel.gameObject.activeSelf == false)
             {
                 canvasCluesPanel.gameObject.SetActive(true);                
             }
         }
     }

     private void OnTriggerStay(Collider other)
     {
         if (other.tag == "Player" && activeClue == true)
         {
             cluePopUpPanel.gameObject.SetActive(true);
             cluePopUpPanel.GetComponentInChildren<Text>().text = this.GetComponent<Text>().text;
             canvasCluesPanel.gameObject.SetActive(false);
         }

         if (other.tag == "Player" && activeClue == false)
         {
             cluePopUpPanel.gameObject.SetActive(false);
             canvasCluesPanel.gameObject.SetActive(true);
         }        
     }

     private void OnTriggerExit(Collider other)
     {
         if (other.tag == "Player" && activeClue == true)
         {
             cluePopUpPanel.gameObject.SetActive(false);
             canvasCluesPanel.gameObject.SetActive(false);
             activeClue = false;
             if(objectsCollected < objects)
             {
                 objectsCollected++;
             }
         }
         else
         {
             cluePopUpPanel.gameObject.SetActive(false);
             canvasCluesPanel.gameObject.SetActive(false);
             activeClue = false;
         }

         canvasHUD.gameObject.SetActive(true);
     }
 }

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Хороший учебник можно найти здесь .

1 - Создайте тип данных

В качестве хорошей практики Храните данные, которые вы хотите сохранить, в классе.Создайте SlotData, вот так.Так что попробуйте конвертировать их так.Этот класс должен иметь атрибут System.Serializable .

Одним из примеров может быть этот

[System.Serializable]
public class SlotData
{
    public bool containsItem = false;
    public string Description;
    //other possible elements
    public int amount; 
}

InventoryData будет просто массивом SlotData.

[System.Serializable]
public class InventoryData
{
    public SlotData[] inventorySlots;
}

2 - настроить данные перед сохранением

Где-то в вашем коде вы обновляете инвентарь.Вы должны настроить эти данные, вероятно, из monobehaviour.В основном вы добавляете всю информацию, которую хотите в своем классе.

public void PrepareToSave()
{
    //setup the inventory
    var yourInventory = new InventoryData();
    //fill all the slots, you must also calculate their amount
    yourInventory.inventorySlots = new SlotData[CalculateYourAmount];
    //fill all the slots here
    for (int   i= 0; i  < CalculateYourAmount;  i++)
    {   
        //fill all the slots
        yourInventory.inventorySlots[i] = CreateTheSlot();
    }

    //this go to the next step
    SaveYourInventory(yourInventory);
}

3 - Сохраните инвентарь

Как вы и просили, вы можете использовать BinaryFormatter и FileStream.

private void SaveYourInventory(InventoryData yourInventory)
{
    var             savePath = Application.persistentDataPath + "/inventory.dat";
    BinaryFormatter bf       = new BinaryFormatter();
    FileStream      file     = File.Create(savePath);
    bf.Serialize(file, yourInventory);
    file.Close();
}

4 - Загрузите инвентарь

Затем вы можете просто загрузить инвентарь следующим образом.

public void LoadYourInventory()
{
    var savePath = Application.persistentDataPath + "/inventory.dat";
    if (File.Exists(savePath))
    {
        BinaryFormatter bf   = new BinaryFormatter();
        FileStream      file = File.Open(savePath, FileMode.Open);
        InventoryData yourInventory = (InventoryData) bf.Deserialize(file);
        file.Close();

        //do what you want with the inventory
        ...
    }
}

Вы также можете найти Менеджер сохраненияsystem здесь .

И если вы хотите продвинуться дальше, вы можете использовать этот оптимизированный форматер (или сохранить его на будущее, если вернетесь к операции сохранения /груз бизнес).

0 голосов
/ 26 июня 2019

Есть много способов сохранить / загрузить ваши данные. Обычно это включает сериализацию ваших данных в какое-то хранилище (память, жесткий диск, сервер по сети и т. Д.) И их чтение.

Я считаю, что самое простое решение - использовать сериализацию JSON ( JSON.NET для Unity - хороший вариант).

Давайте предположим, что мои складские запасы имеют List<Item> Inventory.

Вы помечаете свой класс Item с помощью JsonObjectAttribute(MemberSerialization.OptIn) (чтобы избежать сериализации материала, унаследованного от MonoBehaviour), а каждое свойство, которое вы хотите сохранить вместе с вами, украшается с помощью JsonPropertyAttribute.

Затем вы можете сериализовать ваши данные в PlayerPrefs (это в основном абстракция для хранения данных на локальном устройстве) и загрузить их оттуда.

Псевдокод:

private const string PlayerStatePlayerPrefKey = "PlayerSaveData";

void SavePlayerState(PlayerState state)
{
    var serializedState = JsonConvert.Serialize(state);
    PlayerPrefs.SetString(PlayerStatePlayerPrefKey, serializedState);
    PlayerPrefs.Save();
}

PlayerState LoadPlayerState()
{
    var serializedState = PlayerPrefs.GetString(PlayerStatePlayerPrefKey, null);
    if (serializedState == null)
        return new PlayerState();
    return JsonConvert.DeserializeObject<PlayerState>(serializedState);
}

Вы должны обязательно обернуть весь процесс в Try... Catch и устранить возможные проблемы с сериализацией - наиболее распространенными будут изменения в структуре данных сохраняемых данных, которые будут препятствовать чтению старых сохранений.

Я бы также порекомендовал хранить данные инвентаря в POCO (простой старый объект C #) и отделять данные и логику от визуальных элементов игры.


На несвязанной ноте я предполагаю, что вы относительно новичок в программировании, и я бы посоветовал вам прочитать принцип SOLID и прочитать великую книгу Clean Code .

И некоторые стандарты кодирования, которые я нахожу для очистки своего кода:

Вместо if (boolean == true) просто используйте if(boolean)

Инвертировать и объединить return ifs для удаления вложенности:

private void OnTriggerEnter(Collider other)
{
    if (other.tag == "Player")
    {
        if (canvasCluesPanel.gameObject.activeSelf == false)
        {
            canvasCluesPanel.gameObject.SetActive(true);                
        }
    }
}

Превращается в

private void OnTriggerEnter(Collider other)
{
    if (!other.tag == "Player" || !canvasCluesPanel.gameObject.activeSelf)
        return;
    canvasCluesPanel.gameObject.SetActive(true);    
}

ИМХО Создание игры очень сложно, а наличие более чистого, более понятного кода очень поможет вашему развитию.

Удачи

...