Repository navigation
Item Pickup
Item pickup transfers ground items into the player's existing inventory. Consumables add stock for later use, Gold increases the currency balance, and charms are stored and equipped immediately.
ItemPickupComponent detects nearby ground items and handles pickup requests. Each item's pickUp(Entity player) implementation determines the inventory change; the component then removes the collected entity from the world.
- Move close enough to overlap a ground item's pickup hitbox.
- When Press E — Pick up [item name] appears, press E to collect it.
- Press I to inspect the inventory. Consumables can be equipped or unequipped through the book.
- During gameplay, press Tab to select a consumable slot and Q to use its item.
Overlapping an item makes it available for pickup; contact alone does not collect it. Each E request collects one ground entity, which may represent several units of a stackable item.
E also starts NPC interaction. The input handler sends interact first and requests itemPickup only if an NPC interaction has not started. An already active NPC interaction suppresses the pickup request. While the inventory book is open, Q and E change book pages instead of using or collecting items.
| Item category | Result of picking up a ground item |
|---|---|
| Consumable | Add the full stack quantity to inventory without applying its effect. A newly owned type is assigned to the first empty consumable slot when one is available. |
| Currency | Add the stack quantity to the player's Gold balance and emit a Gold-pickup notification. |
| Charm | Add the individual charm to inventory and equip it immediately, applying its bonus. |
When several items overlap the player, pickup uses the order in which their overlap was recorded. It does not calculate which item is closest. The pickup prompt refers to the same first tracked item.
PlayerFactory attaches ItemPickupComponent to the player alongside HitboxComponent, InventoryComponent and the input component.
Code can request normal pickup through the player's event handler:
player.getEvents().trigger("itemPickup");The component exposes String getPickupPrompt(). It returns the prompt for the first tracked item, or null when no prompt is available. The shared interaction prompt gives NPC prompts priority over item prompts, followed by exit prompts.
- Listen for
collisionStart,collisionEndanditemPickupon the player. - On collision start, check that the player's fixture is its own hitbox, the other fixture includes
PhysicsLayer.ITEM, and the other entity has anItemComponent. - Add that entity to a
LinkedHashSet. Leaving the hitbox removes it from the set. - On a pickup request, resolve the first tracked entity and obtain its
ItemfromItemComponent. - Call the item's pickup method, remove it from the tracked set and dispose of the ground entity:
Item item = itemComponent.getItem();
item.pickUp(entity);
nearbyItems.remove(itemEntity);
itemEntity.dispose();Here, entity is the player that owns the component. Pickup range comes from hitbox overlap; this component has no separate distance setting. If the set is empty, the request does nothing.
The following events use the player entity's event handler:
| Event | Parameters | Role |
|---|---|---|
collisionStart |
Fixture me, Fixture other |
Track an eligible ground item entering the player's hitbox. |
collisionEnd |
Fixture me, Fixture other |
Remove a ground item leaving the player's hitbox. |
itemPickup |
None | Request collection of one tracked ground entity. |
consumableInventoryChanged |
String itemId, Integer count |
Notify observers of the updated consumable count. |
goldChanged |
Integer total |
Notify observers when the Gold balance changes. |
goldPickedUp |
Integer amount |
Report the amount acquired through the Gold-pickup path. |
charmAdded |
Charm charm |
Notify observers when a charm is added to inventory. |
Inventory notifications describe the mutation already performed. Their listeners should update displays or feedback without adding the same reward again.
Item provides the shared pickUp(Entity player) and drop(Entity player) contracts, along with the stable ID, category, texture and quantity. ConsumableItem, CurrencyItem and Charm implement their own pickup behaviour.
ItemComponent holds an item instance. Its constructors accept an Item, a catalog ID, or an ItemDropSpec. getItem(), getItemId() and getQuantity() expose the stored item data; the component itself does not detect collisions or collect anything.
ItemFactory provides:
public static Entity createItem(Item item, Vector2 position)The factory attaches physics, an ITEM-layer hitbox, ItemComponent and ItemDropAnimationComponent. The item texture must already be loaded through ResourceService. The returned entity is not registered automatically; the caller registers it with the entity service to place it in the active world.
Enemy reward creation uses ItemCatalog.createItems to keep consumables and currency as quantity-bearing stacks while expanding non-stackable charms into separate item instances.
ConsumableItem.pickUp calls InventoryComponent.addConsumable(getId(), quantity). Inventory stores quantities by item ID and maintains four consumable-slot assignments.
- Picking up a newly owned type fills the first empty slot when available. If all four slots are occupied, the stock is still added and can be equipped through the inventory book later.
- Picking up more of an already owned type increases its count. It does not assign another slot or automatically re-equip a type that was manually unequipped.
- Unequipping clears the slot assignment without removing stock. Using the final copy clears that type's slot.
The four Consumable Slots display equipped item types and their quantities along the bottom of the screen. Pickup changes inventory data, and the display reads that shared state. Use Inventory UI (Team Five) for equipment controls and slot assignment through the book.
Item use is handled separately by ConsumableSelectionComponent and ConsumableEffectComponent. See Consumables for selection, use requests and effects.
CurrencyItem.pickUp calls InventoryComponent.addGoldFromPickup(quantity). This updates the balance through addGold and reports the positive pickup amount through goldPickedUp.
goldChanged carries the new total balance; goldPickedUp carries the amount just collected. Other balance changes, such as spending Gold, do not become pickup notifications.
Charm.pickUp checks whether that exact instance is already owned, then calls addCharm(this) and setEquipped(player, true). Separate copies of the same charm type remain independent inventory items.
setEquipped(Entity player, boolean equipped) applies or removes the bonus only when the equipment state changes. Unequipping retains ownership. The charm's drop method unequips it and removes it from inventory; it does not create a new ground entity.
Ground pickup and purchasing have different equipment behaviour. The Merchant stores newly purchased charms unequipped and adds purchased consumables without automatically filling an empty slot.
MagnetEffect provides automatic collection for currency and consumables, excluding charms. It scans registered ground items and pulls eligible items towards the player. Collection calls the same Item.pickUp(player) method, so it uses the same inventory and slot rules as normal pickup.
The default Magnet Potion lasts 10 seconds, attracts items within 4 world units, and moves them at 6 world units per second. It collects an item within 0.4 world units, or when the current movement step would reach it.
Magnet collection does not require E or player-hitbox overlap. It schedules the collected ground entity for disposal after the update loop; normal E pickup disposes of the entity immediately.
The pickup implementation and its integration with inventory and input include the following test classes:
CharmPickupComponentTestEnemyLootPickupIntegrationTestItemComponentTestItemPickupUseIntegrationTestInventoryComponentTestKeyboardPlayerInputComponentTestInteractionPromptTestItemFactoryTestConsumableItemTestMagnetUseIntegrationTest