Feat: Add swap, move, & drop items in quick slots
This commit is contained in:
@@ -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
|
// Right Clicks to cancel targeting
|
||||||
this.input.on('pointerdown', (p: Phaser.Input.Pointer) => {
|
this.input.on('pointerdown', (p: Phaser.Input.Pointer) => {
|
||||||
if (p.rightButtonDown() && this.targetingSystem.isActive) {
|
if (p.rightButtonDown() && this.targetingSystem.isActive) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export class QuickSlotComponent {
|
|||||||
private slots: Phaser.GameObjects.Container[] = [];
|
private slots: Phaser.GameObjects.Container[] = [];
|
||||||
private itemMap: (Item | null)[] = new Array(10).fill(null);
|
private itemMap: (Item | null)[] = new Array(10).fill(null);
|
||||||
private assignedIds: string[] = ["health_potion", "pistol", "throwing_dagger", ...new Array(7).fill("")];
|
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) {
|
constructor(scene: Phaser.Scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
@@ -47,17 +49,115 @@ export class QuickSlotComponent {
|
|||||||
}).setOrigin(0, 1);
|
}).setOrigin(0, 1);
|
||||||
|
|
||||||
const slotContainer = this.scene.add.container(x, 0, [g, key]);
|
const slotContainer = this.scene.add.container(x, 0, [g, key]);
|
||||||
|
slotContainer.setData("index", i);
|
||||||
this.slots.push(slotContainer);
|
this.slots.push(slotContainer);
|
||||||
this.container.add(slotContainer);
|
this.container.add(slotContainer);
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
const hitArea = new Phaser.Geom.Rectangle(0, 0, slotSize, slotSize);
|
const hitArea = new Phaser.Geom.Rectangle(0, 0, slotSize, slotSize);
|
||||||
slotContainer.setInteractive(hitArea, Phaser.Geom.Rectangle.Contains);
|
slotContainer.setInteractive(hitArea, Phaser.Geom.Rectangle.Contains);
|
||||||
|
this.scene.input.setDraggable(slotContainer);
|
||||||
|
|
||||||
slotContainer.on("pointerdown", () => {
|
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
|
// Keyboard inputs
|
||||||
this.scene.input.keyboard?.on("keydown-ONE", () => this.activateSlot(0));
|
this.scene.input.keyboard?.on("keydown-ONE", () => this.activateSlot(0));
|
||||||
this.scene.input.keyboard?.on("keydown-TWO", () => this.activateSlot(1));
|
this.scene.input.keyboard?.on("keydown-TWO", () => this.activateSlot(1));
|
||||||
|
|||||||
Reference in New Issue
Block a user