Adding to Array Via Script Instead of in Editor

i have this code, only the part at the top and the Awake function are relevant:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace CoS
{
    public class heroInventory : MonoBehaviour
    {
        public Canvas hinventorycanvas;
        public int invcapacity = 50;
        //public Item[] inventory;
        public ItemHolder[] inventory;


        public Canvas hinvequippedcanvas;

        public GameObject hero;

        public GameObject grounditemprefab;

        private bool inventoryflag = false;

        // Use this for initialization
        void Awake()
        {
            bool inventoryflag = false;

            hinventorycanvas.enabled = false;
            hinvequippedcanvas.enabled = false;
            ItemHolder[] inventory = new ItemHolder[invcapacity];

            //grounditemprefab = new GameObject();
            // going to have to refactor this later.  can't re-initialize inventory at the beginning of every scene!
            //doesn't work anyway
            for (int i = 0; i < invcapacity; i++)
            {
                inventory[i].item = ScriptableObject.CreateInstance("Item") as Item;
                inventory[i].item.objname = "Nothing";
                inventory[i].item.description = "nothing";
                inventory[i].item.price = 0;
                inventory[i].item.sprite = "InvIconNothing";
                inventory[i].item.type = "";
                inventory[i].item.dr_crushing = 0;
                inventory[i].item.dr_cutting = 0;
                inventory[i].item.dr_impaling = 0;
                inventory[i].item.pd_crushing = 0;
                inventory[i].item.pd_cutting = 0;
                inventory[i].item.pd_impaling = 0;
                inventory[i].item.thrusting = "";
                inventory[i].item.swinging = "";
                inventory[i].item.thrusting_modifier = 0;
                inventory[i].item.swinging_modifier = 0;
                inventory[i].quantity = 0;
            }
        }

        // Update is called once per frame
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.I))
            {
               hinvequippedcanvas.enabled = !hinvequippedcanvas.enabled;
            }

            if (inventoryflag)
            {
                ShowInventory();
            }


        }
    
        public void XButton()
        {
            hinventorycanvas.enabled = false;
            inventoryflag = false;
        }

        public void InventoryIconButton()
        {
            hinventorycanvas.enabled = true;
            inventoryflag = true;
           // ShowInventory();
        }

        /**********************
         * Inventory Functions
         * *******************/
        // remove from inventory
        public void Inv_Remove(Item item, int qnty)
        {
            //In the script we will remove an item from the inventory
            var found = -1;
            if (item.objname == "Nothing")
                return;

            //We will check if the item exists and take its place
            for (var i = 0; i < 5; i++)
            {
                //ItemID eyedee1 = (ItemID)i;
                if (inventory[i].item.objname == item.objname) //maybe have a unique id rather than use name?  possibility.
                {
                    found = i;
                    break;
                }
            }

            if (found != -1)
            {
                //If we found the item, we remove it
                inventory[found].quantity -= qnty;//qnty is the amount to remove
                if (inventory[found].quantity <= 0)
                {
                    inventory[found].item = ScriptableObject.CreateInstance("Item") as Item;
                    inventory[found].item.objname = "Nothing";
                    inventory[found].item.description = "nothing";
                    inventory[found].item.price = 0;
                    inventory[found].item.sprite = "InvIconNothing";
                    inventory[found].item.type = "";
                    inventory[found].item.dr_crushing = 0;
                    inventory[found].item.dr_cutting = 0;
                    inventory[found].item.dr_impaling = 0;
                    inventory[found].item.pd_crushing = 0;
                    inventory[found].item.pd_cutting = 0;
                    inventory[found].item.pd_impaling = 0;
                    inventory[found].item.thrusting = "";
                    inventory[found].item.swinging = "";
                    inventory[found].item.thrusting_modifier = 0;
                    inventory[found].item.swinging_modifier = 0;
                }  //If there is no more of the item we change the place to an empty place (Nothing item)
            }
        }

        //In this script we will add items to the inventory
        public void Inv_Add(Item item, int qnty)
        {
            var found = -1;
            bool fullflag = false;

            if (item.objname == "Nothing")
                return;

            for (var i = 0; i < invcapacity; i++)
            {
                if (inventory[i].item.objname == item.objname)
                {
                    found = i; //We affect to found the place of the item if we find it
                    break;
                }
            }

            //If it doesn't exist

            if (found == -1)
            {
                //Let's check if there is an empty place to add our item
                for (var j = 0; j < invcapacity; j++)
                {
                    if (inventory[j].item.objname == "Nothing")
                    {
                        found = j;
                        break;
                    }
                    else if (j == (invcapacity - 1) && found != j)
                    {
                        fullflag = true;
                        break;
                    }
                }
            }

            //should have an "inventory is full" contingency
            if (fullflag)
            {
                // print this out!  in a game-friendly gui - depends on whether looting or picking up, or buying
                Debug.Log("inventory is full, cannot pick up object");
            }

            //Now let's add our item to the place we have *
            if (found != -1)
            {
                inventory[found].item = item; //Argument 0 is the id of the item
                inventory[found].quantity += qnty; //Argument 1 is the amount of the item to add
            }
            // need a script for looting, for buying, and for picking up
        }

        // Drop an item
        public void Inv_Drop(Item item1)
        {
            // item = item clicked in gui - right click and click drop
            //Instantiate(hero, item);
            //not sure what to use in place of "item"
            //use groundobject prefab
            if (item1.objname == "Nothing")
            {
                // show can't drop nothing message or make noise
                return;
            }
            Inv_Remove(item1, 1);
            GameObject gogi = new GameObject();
            gogi = Instantiate(grounditemprefab, new Vector3(0, 0, 0), Quaternion.identity);
            gogi.transform.position = hero.transform.position += new Vector3(1, 1, 0);
            GroundItem grounditem = gogi.GetComponent <GroundItem>();
            grounditem.item = item1;

        }

        //Pick up item
        public void Pick_Up(Item item)
        {
            Inv_Add(item, 1);
        }

    // got to look at GM to figure out the types for the inventory
    void ShowInventory()
        {
            string labeltxt = "";
            string labelimg = "";
            int counter = 0;
            for (int i = 0; i < invcapacity; i++)
            {
                counter = i + 1;
                //update icon and text
                labeltxt = "Text" + counter;
                labelimg = "Image" + counter;

                Text text = GameObject.Find(labeltxt).GetComponent("Text") as Text;
                text.text = inventory[i].item.objname + " x " + inventory[i].quantity;
                Image image = GameObject.Find(labelimg).GetComponent("Image") as Image;
                Sprite invicon = Resources.Load<Sprite>(inventory[i].item.sprite);
                image.sprite = invicon;
            }
        }
    }
}

the awake function does not successfully initialize the array with nothings when i run the game. it needs to be initialized or inventory things don’t work. i originally, when i was using an array of items instead of item holders, initialized it myself in the editor. but i don’t want to make itemholder a scriptable object deriving class. any ideas how i can get this working? sorry i ask so many questions.

edit: also, while i’m at it, i know that some of this code is temporary. i can’t re-initialize the inventory at the beginning of every scene. what would be a permanent solution, not that i’ll implement it right away? should i use a static variable container? i only have one inventory for the party, and a number of merchant inventories that all use the same items.

You’re declaring a local variable called ‘inventory’ in Awake(), thus you do not write to the member-variable with the same name.

1 Like

then how do i assign invcapacity to the array size?

You didn’t understand what he said, I think.
When you write this:

int a;
void Awake() {
  int a = 5;

Your “top” ‘a’ is not 5… it is just 0 (default). It’s because your variable in awake is local.
In your example, you would want to just do:

void Awake() {
inventory = new ItemHolder[invcapacity];

As for initializing them to … basically what amounts to nothing, I’d say another valid option would be to simply set them to null if they aren’t holding anything, or possibly a single scriptable object like “Inventory_Empty”, that one empty object would go in the itemHolder (repeatedly for empty spots, not a new one for each**).

As for moving between scenes, I’d suggest you save the inventory in DontDestroyOnLoad. :slight_smile:

Items that you add in-game, are they asset scriptable objects in the project?

1 Like

items are scriptable objects, but itemholders are monobehaviours.

What I meant specifically is are they assets you’ve created or do you create them “on-the-fly” with create instance? :slight_smile:

1 Like

i create item holders “on the fly”. i’m not sure if this is the best way to do it. i’m not really understanding structurally how this is going to work, unless i can access items i created (these ARE made with scriptable object so are assets) in code.

i don’t use create instance to create item holders though? these would be created with a “new” statement. so maybe this is something wrong with my code.

item holders seem like a good idea but there are still some unanswered questions before i can get this to work.

EDIT: i should add, i get a null reference exception on my create instance code (at the top of the Awake for loop). and i added the line

inventory[i] = new ItemHolder();

at the top of the for loop in Awake above the create instance line. didn’t help the array get initialized but another one of my problems accidentally went away, i think because of updating the script.

Oh okay, so you do make the actual items in the unity editor… that’s all I was wondering about. That’s good.

You can put an item holder on your inventory slot game objects, provided you have slots in the UI. That’s what I do. If your design is different somehow, maybe you could explain it. You shouldn’t create monobehaviours with the ‘new’ keyword :slight_smile: You add it as a component (which is why I suggested just adding it in the UI/editor).

Just to repeat myself from my last post, I still think it would be a good idea to use ‘null’ or a premade scriptable object that is your version of “empty/nothing” (as an item) , instead of just filling in everything every time when you’re adding “nothing” to the inventory setup. :slight_smile:

1 Like

okay, so you’re saying i should add the item holder script to my inventory text objects. i can add a reference for text to the item holder class and assign the item and quantity from there, right? then i don’t need item holder to be a scriptable object? i think this is starting to make sense. the tub time may have helped.

i actually do have a “Nothing” object in my items folder. so i can somehow initialize the array with that i guess? this all brings me further along, but it still bothers me that i don’t know how to initialize an object array in code. and also my toggle inventory code seems to spontaneously stop working, then start working again and i don’t know why. otherwise, i’m good with this and i should finish the inventory coding soon i think, in large part thanks to you methos5k, and also Baste and some others.

I do not know what your “inventory text objects” are, sorry.
— I’m used to an inventory that has, for lack of a better term, little “square slots” where an item can be held :wink:
— is yours like that? lol

But whatever it is, yes you would/could assign the item and quantity on the item holder script.

I was just suggesting that you can add it in the editor, because it’s much easier, imo :slight_smile:

For sure, using a “nothing” object or null is good. I mean, when you assign “nothing” or “null” to the item part of the item holder, not only is it simpler, but it’s easy to compare, too. (or check against for an empty slot, whatever).

i don’t quite get it, but i think my mind is wrapping itself slowly around all this. instead of slots, i have a scrollable list with text boxes that represent each of the 50 inventory slots. each box has the item’s name, an " x ", and the quantity of the item. each “slot” is initialized to “nothing x 0”.

i use an array to hold all the items currently. i need to make a connection between that array of itemholders and the itemholder script on each of the slots. so i’m trying to restructure my inventory code but not quite sure how yet.

Ah okay, so it’s the same idea, just text only… Still, I can safely call them “slots” and believe we’ll understand each other.

I would just try :

ItemHolder [] myInventory = GetComponentsInChildren<ItemHolder>();

so by default all my slots have an itemholder on them, and i just change the item variable and the quantity variable when i want to?

I would imagine so, no? :slight_smile:

1 Like

Thought I’d post something to share if anyone was interested lol…

This is (part of) my design: Few samples I made (UI Scaling, inventory, drag + resize panel)

i have the following code in my heroInventory script, which goes on an empty game object:

ItemHolder[] inventory = hinventorycanvas.GetComponentInChildren<ItemHolder[]>();

hinventorycanvas is the canvas that holds the inventory. the inventory consists of a bunch of text objects with ItemHolder scripts attached. will this work or do i need to do something different? i’m looking for the text objects and they do not have ItemHolder[ ] arrays attached but ItemHolder scripts, so i’m thinking i don’t have this right yet.

i’ll take a look at your project later. it’s about time i have to switch gears and work on school for a bit.

I think you want : GetComponentsInChildren (notice the plural ). and not <ItemHolder[ ]>

1 Like

okay, it seems okay with VS. will test it shortly.

i want to thank you again. if not for people like you my game would have remained a blueprint and never gotten past that stage of development. if you want i can put you in the credits! a lot of people would be in there if i were to be honest.

It’s all good. :slight_smile: Hope it works out for ya.

i tried initializing the inventory to null in Awake(), but getting an index out of array range exception. this does seem like progress, but i’m not sure how to initialize the array in code if i can’t use

ItemHolder[] inventory = new ItemHolder[invcapacity];

in Awake. i can set the size of the array in the inspector, but that doesn’t help me initialize.