Feat: Add swap, move, & drop items in quick slots

This commit is contained in:
Peter Stockings
2026-01-21 14:33:29 +11:00
parent 219c1c8899
commit 9196c49976
2 changed files with 124 additions and 1 deletions

View File

@@ -263,6 +263,29 @@ export class GameScene extends Phaser.Scene {
}
});
this.events.on("drop-item", (data: { itemId: string, pointerX: number, pointerY: number }) => {
if (!this.awaitingPlayer) return;
const player = this.world.actors.get(this.playerId) as CombatantActor;
if (!player || !player.inventory) return;
const item = this.itemManager.getItem(player, data.itemId);
if (!item) return;
// Drop position is simply on the player's current tile
const dropPos = { x: player.pos.x, y: player.pos.y };
// Remove from inventory and spawn in world
if (this.itemManager.removeFromInventory(player, data.itemId)) {
this.itemManager.spawnItem(item, dropPos);
const quantityText = (item.quantity && item.quantity > 1) ? ` x${item.quantity}` : "";
this.dungeonRenderer.showFloatingText(player.pos.x, player.pos.y, `Dropped ${item.name}${quantityText}`, "#aaaaaa");
this.emitUIUpdate();
}
});
// Right Clicks to cancel targeting
this.input.on('pointerdown', (p: Phaser.Input.Pointer) => {
if (p.rightButtonDown() && this.targetingSystem.isActive) {

View File

@@ -7,6 +7,8 @@ export class QuickSlotComponent {
private slots: Phaser.GameObjects.Container[] = [];
private itemMap: (Item | null)[] = new Array(10).fill(null);
private assignedIds: string[] = ["health_potion", "pistol", "throwing_dagger", ...new Array(7).fill("")];
private draggedSlotIndex: number | null = null;
private dragIcon: Phaser.GameObjects.Sprite | null = null;
constructor(scene: Phaser.Scene) {
this.scene = scene;
@@ -47,17 +49,115 @@ export class QuickSlotComponent {
}).setOrigin(0, 1);
const slotContainer = this.scene.add.container(x, 0, [g, key]);
slotContainer.setData("index", i);
this.slots.push(slotContainer);
this.container.add(slotContainer);
// Input
const hitArea = new Phaser.Geom.Rectangle(0, 0, slotSize, slotSize);
slotContainer.setInteractive(hitArea, Phaser.Geom.Rectangle.Contains);
this.scene.input.setDraggable(slotContainer);
slotContainer.on("pointerdown", () => {
this.activateSlot(i);
});
slotContainer.on("pointerup", (pointer: Phaser.Input.Pointer) => {
// If we didn't drag, then activate
if (this.draggedSlotIndex === null && pointer.getDistance() < 10) {
this.activateSlot(i);
}
});
}
// Drag and Drop Events
this.scene.input.on("dragstart", (pointer: Phaser.Input.Pointer, gameObject: Phaser.GameObjects.Container) => {
const index = gameObject.getData("index") as number;
const item = this.itemMap[index];
if (!item) return;
this.draggedSlotIndex = index;
// Setup drag icon
if (!this.dragIcon) {
this.dragIcon = this.scene.add.sprite(0, 0, item.textureKey ?? "items", item.spriteIndex);
this.dragIcon.setDepth(2000).setScale(2.5).setAlpha(0.7);
} else {
this.dragIcon.setTexture(item.textureKey ?? "items", item.spriteIndex);
this.dragIcon.setVisible(true);
}
this.dragIcon.setPosition(pointer.x, pointer.y);
// Ghost the original slot's item
const sprite = gameObject.list.find(child => child instanceof Phaser.GameObjects.Sprite) as Phaser.GameObjects.Sprite;
if (sprite) sprite.setAlpha(0.3);
});
this.scene.input.on("drag", (pointer: Phaser.Input.Pointer) => {
if (this.dragIcon) {
this.dragIcon.setPosition(pointer.x, pointer.y);
}
});
this.scene.input.on("dragend", (pointer: Phaser.Input.Pointer, gameObject: Phaser.GameObjects.Container) => {
if (this.draggedSlotIndex === null) return;
const startIndex = this.draggedSlotIndex;
this.draggedSlotIndex = null;
if (this.dragIcon) this.dragIcon.setVisible(false);
// Reset alpha of original sprite
const sprite = gameObject.list.find(child => child instanceof Phaser.GameObjects.Sprite) as Phaser.GameObjects.Sprite;
if (sprite) sprite.setAlpha(1.0);
// Determine if we dropped on another slot
let targetIndex: number | null = null;
const slotSize = 48;
const slotSpacing = 4;
// Calculate pointer position relative to the quick-slot container
// Since container has scrollFactor(0), its screen position is fixed
const localX = pointer.x - this.container.x;
const localY = pointer.y - this.container.y;
// Check if pointer is within the vertical bounds of the slots
if (localY >= 0 && localY <= slotSize) {
// Calculate which slot index the pointer is over
const index = Math.floor(localX / (slotSize + slotSpacing));
const remainder = localX % (slotSize + slotSpacing);
// Ensure index is valid and pointer is within the slot's actual area (not spacing)
if (index >= 0 && index < 10 && remainder <= slotSize) {
targetIndex = index;
}
}
if (targetIndex !== null && targetIndex !== startIndex) {
// Swap or Move
const temp = this.assignedIds[startIndex];
this.assignedIds[startIndex] = this.assignedIds[targetIndex];
this.assignedIds[targetIndex] = temp;
console.log(`Moved/Swapped slot ${startIndex} to ${targetIndex}`);
} else if (targetIndex === null) {
// Dropped outside - drop on ground
const item = this.itemMap[startIndex];
if (item) {
const gameScene = this.scene.scene.get("GameScene") as any;
gameScene.events.emit("drop-item", {
itemId: item.id,
pointerX: pointer.x,
pointerY: pointer.y
});
// Clear the slot
this.assignedIds[startIndex] = "";
}
}
// Trigger UI refresh to reflect changes on the correct event bus
const gameScene = this.scene.scene.get("GameScene");
gameScene.events.emit("request-ui-update");
});
// Keyboard inputs
this.scene.input.keyboard?.on("keydown-ONE", () => this.activateSlot(0));
this.scene.input.keyboard?.on("keydown-TWO", () => this.activateSlot(1));