Very basic Slot, Inventor and Item..

Hi all my friends!

In these days I have seen many tutorials to create an inventory. I found everything very difficult to assimilate, so today I proceeded to a solution “made at home”. I have a player colliding with a box and a canvas slot appears with an attached image. It collides with another cube and the image disappears.

Create a scene with two cube, a player and a Canvas with slot Image…

Script attach to slot image (canvas image):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Slot : MonoBehaviour
{
     public GameObj gameobj;
     private Image im;
     void Start ()
     {
         im = GetComponent<Image>();
         im.enabled = false;
     }
     public void GetImageFromGameObj()
     {
         im.enabled = true;
       gameobj.imag
         im.sprite = gameobj.imag;
     }
     public void RemoveImageFromGameObj()
     {
         im.enabled = false;
         im.sprite = null;
     }
}

Script Cube AddImage:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameObj : MonoBehaviour {
     public Sprite imag;
     public Slot slot;
     void OnTriggerEnter(Collider other)
     {
         if (other.tag == "Player")
         {
             slot.GetComponent<Slot>().GetImageFromGameObj();
         }
     }
}

Script Cube Remove Image:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameObjRemove : MonoBehaviour
{
     public Slot slot;
     void OnTriggerEnter(Collider other)
     {
         if (other.tag == "Player")
         {
             slot.GetComponent<Slot>().RemoveImageFromGameObj();
         }
     }
}

So far so good, but the image is created in the slot that I choose obviously. Now I would like to create an array of slots in the gui, where to insert images in order of appearance (grab/sort) how to do ?. Frankly, everything is difficult for me to understand …

The idea is to take a key and have your image in the first slot, take a book and have your image in the second slot, etc. (this obviously also when the icons are deleted)…

Could you help me create something really simple and effective?

Thanks!!

Now that you’ve gotten this far, it should be easier to follow some of the more advanced tutorials on youtube.

Thanks for you reply @fire7side :slight_smile:

Yes, I’ve search a simple tut, but I did not find anything. All of hard :frowning:

Today I tried to work on two solutions:

  1. Understanding how to read slots in the inventory
  2. Understand how to transfer images attached to objects in the right place.

To do this, I created an inventory in Canvas where the slots are children. Now with a loop I can read the names of the slots, but I’m freeze on how to make sure that the object I touch transfers the image ( I started studying C# a very short time (I come from simple maxscript) and no, it’s so simple).

In the above examples it has been simpler because I indicate to the cube object to transfer the image into slot 1 or 2 or 3, but how to do it automatically it more difficult for me… any idea?

The basic concept is that the player touches the cube 1 and transfers its image in the first free slot, then touches the cube two which transfers the image that has attached to the second free slot and so on.

So I thought to loop through the slots and find the free one (no sprite attached) but all the solutions I adopted are wrong. I lose something important but I do not understand …

Any help is well accepted! :slight_smile:

Thanks

You will have to look into basic scripting a lot more. Write down, what you need and what you expect and then check out the unity api. So, the way you think is too static and not really object oriented (something you should look into right now!). You have to think of items like objects of the same type but with different content and the same goes for your UI. think of the slots as one object type that you can instantiate at runtime and add to your canvas. There is also already a grid for your canvas that will sort them and so on. There is no simple solution and we can only help you with single problems and not to write down the whole concept of how a inventory system should be build up.

1 Like

Try doing some tutorials to get familiar with scripting and Unity: Learn game development w/ Unity | Courses & tutorials in game design, VR, AR, & Real-time 3D | Unity Learn
https://unity3d.com/learn/beginner-tutorials

You may not got exactly what you want right away, but you will learn the building blocks for how to create your inventory (and many other things) by going this way.

Your idea of looping through until the first free slot is found is perfectly reasonable, by the way. :slight_smile:

1 Like

Thanks for the reply @WheresMommy :slight_smile:

I probably mistake the approach. I always try to do one step at a time, since in many circumstances things are done but they are not understood…
I did not ask how to build an entire inventory (already there are prefab and tut), but on how to have more immediate and simple approaches to understand. For the mini-game I’m building, my solution above would already be fine, but I’m interested in developing the concept with more deep solutions.

Thanks again for your answer and precious directions! :slight_smile:

Thanks @methos5k !!

Yes, these tutorials I watch them often and I am very helpful.
I’m very amateur of C# but I really like learning. I am a 3D modeler and rendering, and this is a new world for me. In 3dsMax I wrote a lot of my plugins, but I find the language much simpler than C # and I still have to enter its reasoning. however, I do not give up and I go ahead to find a solution!!

Thanks again for you reply and link!!!

I continue my discussion here.
I managed with many difficulties to create my small inventory with my slots. Nothing in particular, an object is hit and the attached image is shown in the UI of the canvas in the first slot. I created everything with an array…

void GetSlotArray()
    {
        goArraySlot = GameObject.FindGameObjectsWithTag("Slot").OrderBy(s => s.name).ToArray(); //array sort name

        slot = new Slot[goArraySlot.Length]; //store new array


        for (int i = 0; i < goArraySlot.Length; i++) // loop through all the slots
        {
            if (slot[i] == null) // if slot is empty...
            {
                slot[i] = goArraySlot[i].GetComponent<Slot>(); // get component Slot script
                slot[i].im.sprite = imag; // image from UI image is image from gameobject
                slot[i].im.enabled = true;

                return; 
            }
        }
    }

Now, when I hit two different objects, the image always appears in the first slot, but not the second if the first one is already covered by the sprite etc.

3515540--280963--TestUI.gif

My question is how do I in an array find the next empty slot? It’s all day that I try solutions, I understand that it is a question of loops, but now I’m in total confusion … where am I wrong???

Thanks for any help :slight_smile:

I think if you have your array, whenever you go to pick up an object, go through the array and find the first available slot (index). Simply add the image there. Unless you are really looking for the newest one to be in the first slot; that would mean you’d have to move each object in the array.

So, do you want the most recent image first or was that something you just got working but wasn’t a main goal? :slight_smile:

Yes, I want to take a new free slot in the array by keeping the image in the first slot.
As an example above, I take a book and insert image, I take a HealthDrink and insert the image in a new slot etc.

Well, I would think you don’t want to find them all in a method call or create a new array.

Anyways, if you always want the latest picked up item to be first in the list, you could copy them all “forward” in the array, or you could just move the transform’s sibling index to be first.

Just to be clear, if you had an item in slot #0, and got a new item, you don’t want the new item in slot #1, but you want it in #0 and the item that used to be in #0 is now in #1?
:slight_smile:

Thanks @methos5k for your patience and courtesy :slight_smile:

I search this: If I item in slot #0, the new next item is #1 ecc. ecc.

This is because I have no particular preference and I think to insert more Canvas for the items to be collected. The game I’m creating does not provide a dynamic but static inventory system. I collect the object and show the sprite on the screen. I use the object and I remove the sprite from the screen. and so on…

Thanks again for your tip :slight_smile:

P.S: The Unity API does not provide an array for C# (it is very limited), so even reading the rules of Microsoft net confuses me a lot … :frowning:

Well, arrays are part of C# so you can use them just like you would normally. :slight_smile:

I see, so now with your clarified explanation it’s easier to understand what you want.

Get all of your slots in Start(), or drag n drop them in the inspector.

When you go to add an item, simply loop over your List/array and when you find an empty slot, add your newly collected item there.

Avoid making a new array in the method call & avoid using the ‘Find’ method.

Try this new idea and see how it goes. I think it’ll work well for you. You may want to use a method to get either the Slot or the index. This way you could return null or -1 if the inventory is full, for example.

1 Like

Thanks methos5K, I will try your advice!

I wrote a little bit; not to take away from you learning, but something still pretty basic, if you want to look it over. I tried to keep it cool…

A test scriptable object, which would be sort of a generic “Game Item”
** Please ignore all of the class/script names; I wasn’t creative with them. :slight_smile:

[CreateAssetMenu(menuName ="TestSO1")]
public class TestSO1 : ScriptableObject {

    public string itemName = ""; // didn't even use this in the example.
    public Sprite sprite;
}

Then, a very basic Inventory Manager:

public class Test5 : MonoBehaviour {

    [SerializeField]
    Test6[] slots; // added via the inspector.

    public void AddItem(TestSO1 item)
    {
        int i = GetFreeIndex();
        if(i >= 0)
        {
            slots[i].SetItem(item);
        }
    }
    int GetFreeIndex()
    {
        for(int i = 0; i < slots.Length; ++i)
        {
            if (slots[i].item == null) return i;
        }
        return -1;
    }
}

The slots themselves were in a horizontal layout group in the canvas, just for the record. They are this next script.

public class Test6 : MonoBehaviour {

    public TestSO1 item;

    Image img;

    void Awake()
    {
        img = GetComponent<Image>();
    }

    public void SetItem(TestSO1 newItem)
    {
        item = newItem;
        UpdateSlot();
    }
    void UpdateSlot()
    {
        img.sprite = (item ? item.sprite : null);
    }
}

And last, we have a pickup script. This would be on the world objects. Their variable ‘collectable’ takes one of the test scriptable objects (ie: Game Item) as a field. That’s how it knows what would be picked up. It checks the trigger collider to see if it has the inventory component (Test5, in my examples). If it does, it calls a method on it to add the item it has/is carrying/whatever.

public class Test7 : MonoBehaviour
{
    public TestSO1 collectable;
    void OnTriggerEnter(Collider other)
    {
        Test5 t5 = other.GetComponent<Test5>();
        if (t5)
        {
            if (collectable)
            {
                t5.AddItem(collectable);
                Destroy(gameObject);
            }
        }
    }
}

So, I just thought I’d share. I like inventories. lol :slight_smile:
Maybe you find it helpful. maybe not…

Good luck with yours, either way. :wink:

1 Like

Thanks again for your precious example methos5k!! :slight_smile:

There are some very interesting ideas that I had not thought about!!! Today I will try to do some tests, then I will post updates :slight_smile:

Thanks again !!!

I can not understand why NOTHING works !!! I tried everything :frowning: I’m trying to translate help of methos5k in my scripts, but I can not (p.s: @methos5k your script return null (no work) on my test).

However, place my scripts here as far as I have arrived (if someone can help me find a way to get the free slot next to the full one, I would be happy)

Base Inventory:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq; // used for sort array

public class BaseInventory : MonoBehaviour
{
        GameObject[] goArray;
        public GameObj[] go;

        [SerializeField] private Slot[] slot;

    // Use this for initialization

    void Start ()
        {
            GetComponentArray();
        }

        public void GetObjArray()
        {
            for (int i = 0; i < go.Length; i++)
            {
                if (go[i] != null)
                {
                    go[i].GetComponent<Sprite>();
                }
            }
        }

        void GetComponentArray()
        {
           
            goArray = GameObject.FindGameObjectsWithTag("Item").OrderBy(x => x.name).ToArray();//sort by name array "goArray"
            go = new GameObj[goArray.Length];

            for (int i = 0; i < goArray.Length; i++)
            {
                go[i] = goArray[i].GetComponent<GameObj>();
            }
        }
}

Script attacked at gameobject (Cube) in the scene.
The function “GetSlotArray()” should allow me to find the free slot, but I have a lot of confusion in my mind, because when with “return” I go back to the beginning, everything starts again (I can not find a counting method as demonstrated by methos5k in his example slot script)

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

public class GameObj : MonoBehaviour {

    public Sprite imag;

    GameObject[] goArraySlot;
    [SerializeField] private Slot[] slot;


    private void Start()
    {
        imag = GetComponent<GameObj>().imag;
    }

    void OnTriggerEnter(Collider other)
    {

        if (other.tag == "Player")
        {
            GetSlotArray();
        }
    }

    void GetSlotArray()
    {
        goArraySlot = GameObject.FindGameObjectsWithTag("Slot").OrderBy(s => s.name).ToArray();
        slot = new Slot[goArraySlot.Length];

        for (int i = 0; i < goArraySlot.Length; i++)
        {
     
            if (slot[i] == null)
            {
                slot[i] = goArraySlot[i].GetComponent<Slot>();
                slot[i].im.sprite = imag;
                slot[i].im.enabled = true;

                return;
            }
        }
       
    }

}

Slot:

using System;
using UnityEngine;
using UnityEngine.UI;

public class Slot : MonoBehaviour
{
    public Image im;
   
    // Use this for initialization
    void Start ()
    {
        im = GetComponent<Image>();
        im.enabled = false;
    }
}

Hi MedalHellWay,

Don’t lose heart. You are doing something that is a little tricky to get right. Keep at it and you will get there. :slight_smile:

If you look at the solution provided by methos5k, you will see that in the Inventory Manager (Test5), there is a public method called AddItem. That is what external code will call - nice and simple. Internal to Test5, it will call GetFreeIndex. That is how it is finding the next available slot.

If I look at your code by comparison, in BaseInventory, I see three arrays, which makes me wonder what they are all for? :

    GameObject[] goArray;
    public GameObj[] go;
    [SerializeField] private Slot[] slot;

Also, if I understand corrcetly- you have the object that is picked up (GameObj) looking for a free slot in the InventoryManager. This is not a good OO practice- as a general rule try not to give external classes knowledge of the internals of other classes.

See if you can more closely follow the structure / code organisation that methos5k presented. :slight_smile:

1 Like

Yes, I’m not sure what all of your arrays are for, either.

I will try to explain again my idea in words, without code, so maybe it can help just in English.

When the player runs into a game world object, the script on the world object looks to see if what triggered it has an inventory. If it does, it tells the inventory which item its holding (to add it).
Then, the inventory, which has an array of ‘Slots’, first finds the first available slot, and then calls a method on the Slot’s script to set the item accordingly.
This way things are a little separated, and mostly take care of themselves.

1 Like

First, Thank you both for the patience you show towards me! :smile:

Let’s recap;
The example he posted @methos5k I understood it very well. I did’t want make a copy and paste for my project, I tried to “bend” my script to the idea of methos5k. Here’s where difficulties arise in finding the free slot! :smile: I think it’s better to start all over again!!
In the meantime, since I’m studying C #, I’ve been looking for other solutions such as sort the slots. So, many pieces of code etc., have remained written even if they are useless for the purpose I have to reach.

@Doug_B

    GameObject[] goArray;
    public GameObj[] go;

It’s used to create a new array and to increase the number of slots and grab the Component of script GameObj…

        goArray = GameObject.FindGameObjectsWithTag("Item").OrderBy(x => x.name).ToArray();//sort by name array "goArray"
        go = new GameObj[goArray.Length];

the…

[SerializeField] private Slot[] slot;

t’s a remnant of a slots test (heheheheehhe)

I know, I’m messing around, but I really like programming with graphics, so I’m a bit stubborn !!

Truly a thank you for your help and patience!!!

1 Like