-1

I'm working on a game using Unity Engine and C#. I'm a beginner.

I've created a Custom class called "Item" deriving from scriptable objects that is the basis of items in my game. An object of type Item is held in the 'Inventory', another class, which, contains Add and Remove Functions to add and remove objects of type Item from the inventory. I'm currently working on the Saving and Loading functions for the game, and since I can't save objects of type Item by serializing them to binary and putting them in a persistent data path, I instead have created code that saves the NAME of the item. My question is: How do I create and add an object Item (My custom class) from just the string of its name. (The property Item.name is shared with the actual name of the object in Unity). I've added Comments to my code to hopefully make it easier to understand what I'm trying to do.

Here is the Class Item:

public class Item : ScriptableObject
{

    new public string name = "New Item";
    public Sprite icon = null;
    public bool isDefaultItem = false;
    public virtual void Use()
    {
        Debug.Log("USING: " + name);
    }

    public void RemoveFromInventory()
    {
        Inventory.instance.Remove(this);
    }
}

Here is the Class Inventory, which contains the Add and Remove Functions, taking in an Item:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Text;
    public class Inventory : MonoBehaviour

{
    public static Inventory instance;
    private bool alreadyExists = false;
    public static int space = 20;
    Vector3 playerPosition;
    private void Awake()
    {
        if (instance != null)
        {
        Debug.LogWarning("More than 1 inventory");
        return;
    }

    instance = this;
}
public List<Item> items = new List<Item>();
public static List<string> index = new List<string>();
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;

//These are the functions to add and remove an item to the inventory, Taking in an item, of type Item, from my custom class Item.

public bool Add (Item item)
{
    if (!item.isDefaultItem)
    {

        if (items.Count >= space)
        {
                Debug.Log("NOT ENOUGH SPACE IN INV");
                return false;
        }
        items.Add(item);
        index.Add(item.name);


    }

        if (onItemChangedCallback != null)
            onItemChangedCallback.Invoke();
    return true;
}

public void Remove(Item item)
{
    items.Remove(item);
    index.Remove(item.name);

    if (onItemChangedCallback != null)
        onItemChangedCallback.Invoke();
}


}

Here is the class that actually contains the code in which the problem lies; where I need to somehow instantiate or create an Item and add it to the inventory from the name of the Item. See the LoadInv() for where I need to put it.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;

public class InventoryAttached : MonoBehaviour
{
    public string[] invArray;
    string all;
    //This is the Saving Seperator
    char[] delimiter = { '.' };
    public void SaveInv()
    {
        InvSaveSystem.SaveInv(this);
    }

    public void LoadInv()
    {
        //Code that gets data for the items that need to be added to the inventory
        InvData data = InvSaveSystem.LoadInv(); //This is the Data from my binary formatter
        all = ConvertStringArrayToString(data.invSlot); 
        invArray = all.Split(delimiter);

        //For loop that iterates through the inventory array containing the names of the items stored in the inventory
        for (int i = 0; i < invArray.Length; i++)
        {
            Debug.Log(invArray[i]);
            //Here, I would like to use my Add function to add the items to the inventory
            // It would look something like this: Inventory.instance.Add(invArray[i[]);
        }

    }


    static string ConvertStringArrayToString(string[] array) //Converter Code used to convert to and from string arrays
    {
        // Concatenate all the elements into a StringBuilder.
        StringBuilder builder = new StringBuilder();
        foreach (string value in array)
        {
            builder.Append(value);
            builder.Append('.');
        }
        return builder.ToString();
    }

    static string ConvertStringArrayToStringJoin(string[] array)
    {
        // Use string Join to concatenate the string elements.
        string result = string.Join(".", array);
        return result;
    }
}

Just for reference, here is the class InvData, which contains the string array that My saving system formats into binary and saves to the HD.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using System.Text.RegularExpressions;
[System.Serializable]
public class InvData

{
    public string[] invSlot;


    public InvData(InventoryAttached inv)
    {
        invSlot = new string[Inventory.index.Count];

        for (int i = 0; i < Inventory.index.Count; i++)
        {
            invSlot[i] = Inventory.index[i];
        }
    }



}
  • 1
    `since I can't save objects of type Item by serializing them to binary and putting them in a persistent data path` why not? – TheBatman Mar 11 '20 at 15:32
  • @TheBatman because my Custom class Item derives from Scriptable Objects in Unity, which isn't System.Serializable. – Lee Jordan Mar 11 '20 at 15:34
  • Ignoring the architectural issues with this design and addressing just the question asked, I would create an `ItemFactory` class with a `Create(string itemName)` method that enumerates a collection of string to type mappings. Finally use System.Activator to create the instance. – Chris Pickford Mar 11 '20 at 15:57
  • @ChrisPickford I'm completely self-taught, so I'm not sure what standard architectural convention is for this sort of thing, sorry. Also, further on me being a beginner, I'm not exactly sure how to do what your solution is suggesting. Could you either explain it in an answer format, or link me to a resource that provides an example and how to do it? Thanks. – Lee Jordan Mar 11 '20 at 16:02
  • @LeeJordan Don't worry everybody starts somewhere. Look up the abstract factory pattern and go from there. – Chris Pickford Mar 11 '20 at 16:08
  • @ChrisPickford This is a bit over my head... I just figured out how to use a for loop yesterday. I will keep working though. – Lee Jordan Mar 11 '20 at 16:21
  • Why do you need a ScriptableObject if anyway you rather want it to access globally via the `instance`? You could actually simply make it a `public static class` instead or use a Singleton manager to take care of the instance .. no need for making it a `ScriptableObject` they way you are using it... In general afaik `Awake` is only called when **creating** the SO .. Try `OnEnable` instead! Note that a SO ist completely stripped from the build if it nowhere reference! And unloaded from memory if not referenced in the active scene! – derHugo Mar 11 '20 at 17:01
  • @derHugo I need it to be a Scriptable object so I can create it easily, and use it easily. The game is an RPG, and I need to create items such as potions and armor. Item is simply a class to facilitate such needs. Are you suggesting that there's a better way to do that? – Lee Jordan Mar 11 '20 at 17:12
  • I am saying that `ScriptableObject` make sense if you want to reference them somewhere and use multiple instances with different values mainly from within the Editor .. in your case you could simply use a "normal" `[Serializable] public class Item` and create instances using as usual `new Item();` you could even add a constructor to make things prettier .. Then if younhave a wrapper class such as `[Serializable] public class ItemList { public List items;}` you could populate it in one go using e.g. JsonUtility ... – derHugo Mar 11 '20 at 17:24
  • @derHugo That would work, yes, but I can't convert Items into binary and save them, which is how my saving system works. [System.Serializable] – Lee Jordan Mar 11 '20 at 23:15
  • `I can't convert Items into binary` .. why not? As said if you set it incorrectly you can completely serialized and Deserialize the content of your list to/from JSON. This is a string of could then simply read/write from/to your file and even encrypt it if needed ... – derHugo Mar 12 '20 at 06:08
  • Btw still not sure where your question is going exactly but if it is about how to create instances of `Item` at runtime you should have a look at [`ScriptableObject.CreateInstance()`](https://docs.unity3d.com/ScriptReference/ScriptableObject.CreateInstance.html) – derHugo Mar 12 '20 at 06:23

1 Answers1

-1

.AddComponent(Type.GetType("type_name"));