Drag and Drop Inventory with LibGDX (Part I)

This part of the inventory tutorial series is about the base classes to handle the logic, store the inventory information and manage them.

The Items

First we need to define what an Item is. For us it is just an enum. Additionally the enum has a String value which is the name of the TextureRegion in our TextureAtlas with all icon textures. The atlas files can be checked out here.

public enum Item {
    CRYSTAL_RED("redcrystal"), CRYSTAL_BLUE("bluecrystal"), CRYSTAL_GREEN("greencrystal"),
    CRYSTAL_YELLOW("yellowcrystal"), CRYSTAL_MAGENTA("magentacrystal"),
    CRYSTAL_CYAN("cyancrystal"), CRYSTAL_ORANGE("orangecrystal"), ...;

    private String textureRegion;

    private Item(String textureRegion) {
        this.textureRegion = textureRegion;
    }

    public String getTextureRegion() {
        return textureRegion;
    }
}

The slots

To support stacked items, our inventory Slots won’t only have an Item type, but also the number of items. The class itself is pretty simple as it only manages those two variables with an add(...) and take(...) method. What the SlotListener does is described in the next paragraph.

public class Slot {

    private Item item;

    private int amount;

    private Array<SlotListener> slotListeners = new Array<SlotListener>();

    public Slot(Item item, int amount) {
        this.item = item;
        this.amount = amount;
    }

    public boolean isEmpty() {
        return item == null || amount <= 0;
    }

    public boolean add(Item item, int amount) {
        if (this.item == item || this.item == null) {
            this.item = item;
            this.amount += amount;
            notifyListeners();
            return true;
        }

        return false;
    }

    public boolean take(int amount) {
        if (this.amount >= amount) {
            this.amount -= amount;
            if (this.amount == 0) {
                item = null;
            }
            notifyListeners();
            return true;
        }

        return false;
    }

    public void addListener(SlotListener slotListener) {
        slotListeners.add(slotListener);
    }

    public void removeListener(SlotListener slotListener) {
        slotListeners.removeValue(slotListener, true);
    }

    private void notifyListeners() {
        for (SlotListener slotListener : slotListeners) {
            slotListener.hasChanged(this);
        }
    }

    public Item getItem() {
        return item;
    }

    public int getAmount() {
        return amount;
    }

    @Override
    public String toString() {
        return "Slot[" + item + ":" + amount + "]";
    }
}

Furthermore we have a little interface called SlotListener which makes it possible to trigger some actions when the slot has changed.

public interface SlotListener {

    /**
    * Will be called whenever the slot has changed.
    */
    void hasChanged(Slot slot);

}    

The inventory

The Inventory manages a bunch of Slots. In this case we create 25 Slots and add a few random Items.

public class Inventory {

    private Array<Slot> slots;

    public Inventory() {
        slots = new Array<Slot>(25);
        for (int i = 0; i < 25; i++) {
            slots.add(new Slot(null, 0));
        }

        // create some random items
        for (Slot slot : slots) {
            slot.add(Item.values()[MathUtils.random(0, Item.values().length - 1)], 1);
        }

        // create a few random empty slots
        for (int i = 0; i < 3; i++) {
            Slot randomSlot = slots.get(MathUtils.random(0, slots.size - 1));
            randomSlot.take(randomSlot.getAmount());
        }
    }

    public int checkInventory(Item item) {
        int amount = 0;

        for (Slot slot : slots) {
            if (slot.getItem() == item) {
                amount += slot.getAmount();
            }
        }

        return amount;
    }

    public boolean store(Item item, int amount) {
        // first check for a slot with the same item type
        Slot itemSlot = firstSlotWithItem(item);
        if (itemSlot != null) {
            itemSlot.add(item, amount);
            return true;
        } else {
            // now check for an available empty slot
            Slot emptySlot = firstSlotWithItem(null);
            if (emptySlot != null) {
                emptySlot.add(item, amount);
                return true;
            }
        }

        // no slot to add
        return false;
    }

    public Array<Slot> getSlots() {
        return slots;
    }

    private Slot firstSlotWithItem(Item item) {
        for (Slot slot : slots) {
            if (slot.getItem() == item) {
                return slot;
            }
        }

        return null;
    }

}

Next

In Part II of this tutorial series, we are going to leverage this basic inventory system onto a scene2d.ui layer to actually display the inventory.

Leave a Reply

Your email address will not be published. Required fields are marked *