0
\$\begingroup\$

In a game like Minecraft, the player could have any of several hundred types of items in their inventory. Players can drop those items into the world, but obviously how they're rendered in the world differs from how they're rendered in the inventory.

I'm trying to understand how to design for this scenario using Unity's GameObject concept.

Individually, it seems like the expectation is that:

  • I would have one GameObject (with at least a SpriteRenderer) for every unique item that can appear in-world.
  • I would have one GameObject (with at least an Image component) for every unique item that can appear in inventories.

With so many, I also need to come up with some sort of directory so that I can associate bulk prefab objects for use in-game.

Is this accurate? I feel like that's a lot of overhead.

Would I be able to create one GameObject with both a SpriteRenderer and an Image and maybe toggle between then based on whether its in world or an inventory?

I had also considered using one generic GameObject and replacing the sprite/image based on the item needed, but that feels like it's misusing what GameObjects are meant for. It also likely subverts the benefit of pooling them, etc.

Is there another approach I'm missing?

\$\endgroup\$
1
\$\begingroup\$

How about this:

  • Create a struct/class, that has one Sprite and one Mesh/Image (depending what your items looks like in the world). Create a script that has a list of those classes. Give data to this script, in pairs, like list.add( new MyClass(catSprite, catMesh) ); for each object that exists in your game.

  • Your items have now IDs based on their index in the array, in the above example, list[0] would be the cat object.

  • Now create two scripts, one handles an item in the world, and how it behaves (maybe when you drop it, it bounces around, or it shines to indicate it's an interactive item) and the other handles an item in the inventory (it occupies a slot, and you can move it around or interact with it either with use or destroy etc).

Now for example, when you destroy a block, or kill an enemy, and you want to summon a new item, you simply do something like MyItemScript.SummonItem(id, location); which would (most likely) Instantiate a prefab of an item, and change it's Mesh / Image to match that of that item's id.

Do the same for an inventory item. When you pick up an item from the floor, do something like MyInventoryItemScript.SummonItem(id, slot); which would Instantiate a prefab of an inventory item, with the sprite from the item's id and then destroy the item on the world.

Please note this is not the only way of doing this, and depends on your exact situation, but it can probably give you some vague idea of where to go next.

\$\endgroup\$
0
\$\begingroup\$
  1. Create a prefab with a Sprite or Image component.
  2. Clone/Instantiate this prefab as needed
  3. Set the sprite/image to the desired image file from Resources

For example, I have this helper function that I apply directly to an Image component.

public static Sprite getSpriteForResource(string texName) {
    //Debug.Log(texName);
    Texture2D t = t = Resources.Load<Texture2D>(texName);
    if(t == null) {
        Exception err = new Exception("Unable to load image file '" + texName + "'");
        Configuration.writeToErrorFile("MainThreadErrors.txt", err.ToString());
        return null;
    }
    Rect size = new Rect(0, 0, t.width, t.height);
    return Sprite.Create(t, size, new Vector2(0.5f,0.5f), PIXELS_PER_UNIT, 0, SpriteMeshType.FullRect);
    //PIXELS_PER_UNIT = 100
    //Matches the ReferencePixelsPerUnit property on the Canvas
}

and

img.GetComponent<Image>().sprite = SpriteLoader.getSpriteForResource("items/" + item.name);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.