Files
CINC/ui/InventoryUI.js
T

1264 lines
40 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 背包UI组件:负责显示背包界面和处理用户交互
export class InventoryUI {
constructor(scene, inventory, cellSize = 40) {
this.scene = scene;
this.inventory = inventory;
this.cellSize = cellSize;
this.isOpen = false;
this.selectedItem = null;
this.hoveredCell = null;
// 拖动相关属性
this.isDragging = false;
this.draggedItem = null;
this.draggedSprite = null;
this.dragOffset = { x: 0, y: 0 };
this.container = null;
this.gridCells = [];
this.itemSprites = new Map();
// 计算背包位置(相机右侧)
this.calculatePosition();
this.createUI();
// 添加全局鼠标移动事件监听
this.scene.input.on('pointermove', (pointer) => {
this.onMouseMove(pointer);
});
// 添加全局鼠标释放事件监听
this.scene.input.on('pointerup', (pointer) => {
this.onMouseUp(pointer);
});
}
/**
* 计算背包位置(屏幕左上角)
*/
calculatePosition() {
// 背包宽度
const inventoryWidth = this.inventory.width * this.cellSize + 20;
// 固定在屏幕左上角,有一定边距
this.x = 20;
this.y = 20;
}
/**
* 创建背包UI
*/
createUI() {
// 创建容器
this.container = this.scene.add.container(this.x, this.y);
this.container.setDepth(100);
this.container.setScrollFactor(0); // 固定在屏幕上,不随相机移动
// 创建背景
const background = this.scene.add.rectangle(
0, 0,
this.inventory.width * this.cellSize + 20,
this.inventory.height * this.cellSize + 20,
0x333333, 0.9
);
background.setOrigin(0, 0);
background.setScrollFactor(0); // 固定在屏幕上
background.setDepth(-1); // 确保背景在所有内容下方
// 添加交互,阻止点击事件穿透到下方地图
background.setInteractive();
background.on('pointerdown', (pointer) => {
return false; // 阻止事件冒泡
});
background.on('pointerover', (pointer) => {
return false; // 阻止事件冒泡
});
background.on('pointerout', (pointer) => {
return false; // 阻止事件冒泡
});
this.container.add(background);
// 创建网格
this.createGrid();
// 创建关闭按钮
this.createCloseButton();
// 创建统计信息
this.createStats();
// 初始化时隐藏
this.hide();
}
/**
* 创建背包网格
*/
createGrid() {
const offsetX = 10;
const offsetY = 10;
for (let y = 0; y < this.inventory.height; y++) {
this.gridCells[y] = [];
for (let x = 0; x < this.inventory.width; x++) {
const cellX = offsetX + x * this.cellSize;
const cellY = offsetY + y * this.cellSize;
// 创建单元格
const cell = this.scene.add.rectangle(cellX, cellY, this.cellSize, this.cellSize, 0x666666, 0.5);
cell.setOrigin(0, 0);
cell.setStrokeStyle(1, 0xffffff);
cell.setScrollFactor(0); // 固定在屏幕上,不随相机移动
// 添加交互
cell.setInteractive();
// 绑定点击事件
cell.on('pointerdown', (pointer) => {
console.log('单元格点击事件触发:', { x, y });
this.onCellClicked(x, y);
return false; // 阻止事件冒泡
});
cell.on('pointerover', (pointer) => {
this.onCellHovered(x, y);
return false; // 阻止事件冒泡
});
cell.on('pointerout', (pointer) => {
this.onCellUnhovered();
return false; // 阻止事件冒泡
});
this.container.add(cell);
this.gridCells[y][x] = cell;
}
}
}
/**
* 创建关闭按钮
*/
createCloseButton() {
const buttonX = this.inventory.width * this.cellSize + 25;
const buttonY = 10;
const button = this.scene.add.text(buttonX, buttonY, 'X', {
font: '24px Arial',
fill: '#ffffff'
});
button.setInteractive({
useHandCursor: true
});
button.on('pointerdown', (pointer) => {
this.hide();
return false; // 阻止事件冒泡
});
button.on('pointerover', (pointer) => {
button.setFill('#ff0000');
return false; // 阻止事件冒泡
});
button.on('pointerout', (pointer) => {
button.setFill('#ffffff');
return false; // 阻止事件冒泡
});
this.container.add(button);
}
/**
* 创建统计信息
*/
createStats() {
const statsX = this.inventory.width * this.cellSize + 30;
const statsY = 50;
// 创建统计信息背景
const statsBackground = this.scene.add.rectangle(
statsX - 20,
statsY - 20,
120, 100,
0x222222, 0.9
);
statsBackground.setOrigin(0, 0);
statsBackground.setScrollFactor(0);
// 添加交互,阻止事件穿透
statsBackground.setInteractive();
statsBackground.on('pointerdown', (pointer) => {
return false; // 阻止事件冒泡
});
this.container.add(statsBackground);
this.statsText = this.scene.add.text(statsX, statsY, '', {
font: '12px Arial',
fill: '#ffffff'
});
this.container.add(this.statsText);
this.updateStats();
}
/**
* 更新统计信息
*/
updateStats() {
const stats = this.inventory.getStats();
this.statsText.setText([
`物品数量: ${stats.totalItems}`,
`总重量: ${stats.totalWeight.toFixed(1)}`,
`总体积: ${stats.totalVolume.toFixed(1)}`,
`空位数: ${stats.emptySlots}`
]);
}
/**
* 物品精灵点击事件
* @param {Object} item - 点击的物品
*/
onItemSpriteClicked(item) {
console.log('onItemSpriteClicked:', item.name, 'ID:', item.id);
// 如果是右键点击,使用物品
if (this.scene.input.mousePointer.rightButtonDown()) {
console.log('右键点击物品,使用物品:', item.name);
this.useItem(item);
} else if (this.selectedItem && this.selectedItem.id === item.id) {
// 如果是左键点击已选中的物品,取消选择
console.log('左键点击已选中物品,取消选择:', item.name);
this.deselectItem();
} else {
// 如果是左键点击其他物品,选中当前物品
// 如果已经有选中的物品,先取消选择
if (this.selectedItem) {
console.log('已有选中物品,先取消选择:', this.selectedItem.name);
this.deselectItem();
}
// 选中当前物品
console.log('选中物品:', item.name);
this.selectItem(item);
}
}
/**
* 使用物品
* @param {Object} item - 要使用的物品
*/
useItem(item) {
console.log('useItem:', item.name, 'ID:', item.id);
// 获取当前选中的角色(假设场景中有player属性)
const user = this.scene.player;
if (user) {
console.log('使用物品的角色:', user.name);
// 确保物品有场景引用
item.scene = this.scene;
console.log('DEBUG: 设置物品场景引用:', item.scene ? '成功' : '失败');
// 调用物品的useFromInventory方法,从背包中使用物品
// 注意:物品的具体使用方法(如useSeed)中会处理从背包移除的逻辑
item.useFromInventory(user);
// 更新UI,因为物品可能已经被移除
this.updateUI();
// 对于种子类型的物品,延迟取消选择,避免背包立即关闭导致用户体验不佳
// 这样用户可以看到种植模式的变化
if (item.type !== 'seed') {
// 非种子类型物品,立即取消选择
this.deselectItem();
} else {
// 种子类型物品,延迟取消选择,给用户视觉反馈
console.log('种子物品使用后,延迟取消选择');
// 不立即取消选择,让用户看到种植模式的变化
// 种植模式会在后续操作中自动取消选择
}
} else {
console.log('没有选中的角色,无法使用物品');
}
}
/**
* 物品精灵鼠标按下事件,用于记录点击状态和位置
* @param {Object} item - 物品
* @param {Phaser.Input.Pointer} pointer - 指针对象
*/
onItemSpriteDown(item, pointer) {
console.log('onItemSpriteDown:', item.name, '记录点击位置');
// 右键点击直接使用物品,不处理选择和拖动
if (pointer.rightButtonDown()) {
console.log('右键点击物品精灵,使用物品:', item.name);
this.useItem(item);
return; // 直接返回,不处理后续逻辑
}
// 左键点击处理选择和拖动
// 记录点击的物品和位置,用于判断是否开始拖动
this.clickItem = item;
this.clickPosition = { x: pointer.x, y: pointer.y };
this.clickTime = Date.now();
// 切换选择状态:如果已选中,则取消选择;如果未选中,则选中
if (this.selectedItem && this.selectedItem.id === item.id) {
// 如果点击的是已选中物品,取消选择
console.log('左键点击已选中物品精灵,取消选择:', item.name);
this.deselectItem();
} else {
// 如果没有选中物品或点击的是另一个物品,选中当前物品
if (this.selectedItem) {
this.deselectItem();
}
this.selectItem(item);
}
// 不立即开始拖动,只在鼠标移动超过阈值时才开始
this.isDragging = false;
this.draggedItem = null;
this.draggedSprite = null;
}
/**
* 全局鼠标移动事件处理
* @param {Phaser.Input.Pointer} pointer - 指针对象
*/
onMouseMove(pointer) {
// 如果还没有开始拖动,检查是否应该开始拖动
if (this.clickItem && !this.isDragging) {
const distance = Math.sqrt(
Math.pow(pointer.x - this.clickPosition.x, 2) +
Math.pow(pointer.y - this.clickPosition.y, 2)
);
// 如果移动距离超过阈值,开始拖动
if (distance > 5) {
this.startDragging();
}
}
// 如果正在拖动,更新精灵位置,使其中心锁定在鼠标位置
if (this.isDragging && this.draggedSprite) {
// 更新拖动精灵的位置,使其中心锁定在鼠标位置
const spriteX = pointer.x - this.container.x - this.spriteCenterOffset.x;
const spriteY = pointer.y - this.container.y - this.spriteCenterOffset.y;
this.draggedSprite.setPosition(spriteX, spriteY);
// 检查鼠标是否悬停在某个单元格上
this.updateDragHover(pointer);
}
}
/**
* 开始拖动物品
*/
startDragging() {
console.log('startDragging:', this.clickItem.name);
this.isDragging = true;
this.draggedItem = this.clickItem;
// 拖动时隐藏物品详情
this.hideItemInfo();
// 获取物品精灵
const spriteObj = this.itemSprites.get(this.draggedItem.id);
if (spriteObj) {
this.draggedSprite = spriteObj.sprite;
// 获取精灵尺寸
const spriteRect = this.draggedSprite.getBounds();
// 计算精灵中心偏移(用于后续位置计算)
this.spriteCenterOffset = {
x: spriteRect.width / 2,
y: spriteRect.height / 2
};
// 提升精灵深度,确保拖动时显示在最上层
this.draggedSprite.setDepth(10);
// 创建预计放下位置的预览精灵
this.createDragPreview();
}
}
/**
* 创建预计放下位置的预览
*/
createDragPreview() {
if (this.dragPreview) {
this.dragPreview.destroy();
this.dragPreview = null;
}
const { width, height } = this.draggedItem.gridSize;
const previewWidth = width * this.cellSize;
const previewHeight = height * this.cellSize;
// 创建预览矩形(半透明,用于显示预计放下位置)
this.dragPreview = this.scene.add.rectangle(0, 0, previewWidth, previewHeight, 0xffffff, 0.3);
this.dragPreview.setOrigin(0, 0);
this.dragPreview.setStrokeStyle(2, 0x00ff00, 1);
this.dragPreview.setScrollFactor(0); // 固定在屏幕上
this.dragPreview.setDepth(5); // 确保预览在背景之上,在拖动的精灵之下
this.container.add(this.dragPreview);
}
/**
* 更新预计放下位置的预览
* @param {number} centerX - 预计放下的中心X坐标
* @param {number} centerY - 预计放下的中心Y坐标
*/
updateDragPreview(centerX, centerY) {
if (!this.dragPreview || !this.draggedItem) return;
const { width, height } = this.draggedItem.gridSize;
// 计算预计放下位置的左上角坐标
const topLeftX = Math.floor(centerX - (width - 1) / 2);
const topLeftY = Math.floor(centerY - (height - 1) / 2);
// 更新预览位置
const previewX = 10 + topLeftX * this.cellSize;
const previewY = 10 + topLeftY * this.cellSize;
this.dragPreview.setPosition(previewX, previewY);
// 根据是否可以放置更新预览颜色
const canPlace = this.inventory.canPlaceItem(this.draggedItem, centerX, centerY);
if (canPlace) {
this.dragPreview.setFillStyle(0x00ff00, 0.3);
this.dragPreview.setStrokeStyle(2, 0x00ff00, 1);
} else {
this.dragPreview.setFillStyle(0xff0000, 0.3);
this.dragPreview.setStrokeStyle(2, 0xff0000, 1);
}
}
/**
* 销毁预计放下位置的预览
*/
destroyDragPreview() {
if (this.dragPreview) {
this.dragPreview.destroy();
this.dragPreview = null;
}
}
/**
* 更新拖动时的悬停状态和预览位置
* @param {Phaser.Input.Pointer} pointer - 指针对象
*/
updateDragHover(pointer) {
// 计算鼠标在背包容器内的位置
const localX = pointer.x - this.container.x;
const localY = pointer.y - this.container.y;
// 计算对应的单元格坐标
const cellX = Math.floor((localX - 10) / this.cellSize);
const cellY = Math.floor((localY - 10) / this.cellSize);
// 检查坐标是否在背包范围内
if (cellX >= 0 && cellX < this.inventory.width && cellY >= 0 && cellY < this.inventory.height) {
// 更新悬停单元格
if (!this.hoveredCell || this.hoveredCell.x !== cellX || this.hoveredCell.y !== cellY) {
// 移除之前的悬停效果
if (this.hoveredCell) {
this.onCellUnhovered();
}
// 设置新的悬停单元格
this.onCellHovered(cellX, cellY);
}
// 更新预计放下位置的预览
this.updateDragPreview(cellX, cellY);
// 确保预览可见
if (this.dragPreview) {
this.dragPreview.setVisible(true);
}
} else {
// 鼠标移出背包范围,移除悬停效果
if (this.hoveredCell) {
this.onCellUnhovered();
}
// 隐藏预览
if (this.dragPreview) {
this.dragPreview.setVisible(false);
}
}
}
/**
* 全局鼠标释放事件处理
* @param {Phaser.Input.Pointer} pointer - 指针对象
*/
onMouseUp(pointer) {
// 如果正在拖动,处理拖动结束
if (this.isDragging && this.draggedItem) {
console.log('onMouseUp: 结束拖动');
// 计算鼠标在背包容器内的位置
const localX = pointer.x - this.container.x;
const localY = pointer.y - this.container.y;
// 计算对应的单元格坐标
const cellX = Math.floor((localX - 10) / this.cellSize);
const cellY = Math.floor((localY - 10) / this.cellSize);
// 尝试将物品放置到新位置
let success = false;
// 检查坐标是否在背包范围内
if (cellX >= 0 && cellX < this.inventory.width && cellY >= 0 && cellY < this.inventory.height) {
const targetItem = this.inventory.getItemAt(cellX, cellY);
// 检查新位置是否与旧位置完全相同
const isSamePosition = this.draggedItem.position.x === cellX && this.draggedItem.position.y === cellY;
// 如果目标位置是物品原来的位置且位置完全相同,直接取消拖动
if (targetItem && targetItem.id === this.draggedItem.id && isSamePosition) {
console.log('拖动到原起始位置,直接取消拖动');
success = true;
} else if (targetItem) {
if (targetItem.id === this.draggedItem.id) {
// 如果目标位置是当前拖动物品的非起始位置,尝试移动
console.log('拖动到当前物品的非起始位置,尝试移动:', this.draggedItem.name, '到位置:', { cellX, cellY });
success = this.inventory.moveItem(this.draggedItem.id, cellX, cellY);
console.log('移动结果:', success);
} else {
// 如果目标位置有其他物品,尝试交换
success = this.inventory.swapItems(this.draggedItem.id, targetItem.id);
}
} else {
// 如果目标位置是空的,尝试移动
success = this.inventory.moveItem(this.draggedItem.id, cellX, cellY);
}
} else {
// 鼠标释放位置不在背包范围内,执行丢弃操作
console.log('拖动出背包,执行丢弃操作:', this.draggedItem.name);
// 获取物品ID和基本信息
const itemId = this.draggedItem.itemTypeId || this.draggedItem.id;
// 从背包中移除物品
const removedItem = this.inventory.removeItem(this.draggedItem.id);
if (removedItem) {
// 在角色位置创建该物品
if (this.scene.itemManager) {
const player = this.scene.player;
this.scene.itemManager.createItem(itemId, player.x, player.y);
console.log('已在角色位置创建丢弃的物品:', removedItem.name);
}
success = true;
}
}
// 销毁预计放下位置的预览
this.destroyDragPreview();
// 重置拖动状态
this.isDragging = false;
if (this.draggedSprite) {
this.draggedSprite.setDepth(1); // 恢复精灵深度
this.draggedSprite = null;
}
// 更新UI
if (success) {
this.deselectItem();
this.updateUI();
} else {
// 如果移动失败,重置精灵位置
this.updateUI();
}
this.draggedItem = null;
this.spriteCenterOffset = null;
// 移除悬停效果
if (this.hoveredCell) {
this.onCellUnhovered();
}
}
// 重置点击状态
this.clickItem = null;
this.clickPosition = null;
this.clickTime = null;
}
/**
* 单元格点击事件
* @param {number} x - 单元格X坐标
* @param {number} y - 单元格Y坐标
*/
onCellClicked(x, y) {
console.log('onCellClicked:', { x, y });
const item = this.inventory.getItemAt(x, y);
if (this.selectedItem) {
console.log('已有选中物品:', this.selectedItem.name, 'ID:', this.selectedItem.id);
// 如果点击的是已选中物品,直接取消选择(无论点击的是哪个位置)
if (item && item.id === this.selectedItem.id) {
console.log('点击已选中物品,取消选择:', item.name);
this.deselectItem();
return;
}
// 尝试移动或交换物品
let success = false;
if (item) {
// 如果点击的是另一个物品,尝试交换
console.log('点击另一个物品,尝试交换:', item.name, 'ID:', item.id);
success = this.inventory.swapItems(this.selectedItem.id, item.id);
console.log('交换结果:', success);
} else {
// 如果点击的是空位,尝试移动
console.log('点击空位,尝试移动物品:', this.selectedItem.name, '到位置:', { x, y });
success = this.inventory.moveItem(this.selectedItem.id, x, y);
console.log('移动结果:', success);
}
if (success) {
// 只有操作成功时才取消选择并更新UI
console.log('操作成功,取消选择并更新UI');
this.deselectItem();
this.updateUI();
} else {
console.log('操作失败,保持选择状态');
}
} else if (item) {
// 如果没有选中的物品,选中点击的物品
console.log('没有选中物品,选中点击的物品:', item.name);
this.selectItem(item);
} else {
console.log('点击空位,没有选中物品,无操作');
}
}
/**
* 单元格悬停事件
* @param {number} x - 单元格X坐标
* @param {number} y - 单元格Y坐标
*/
onCellHovered(x, y) {
this.hoveredCell = { x, y };
// 高亮显示悬停的单元格
this.gridCells[y][x].setFillStyle(0x888888, 0.7);
// 只有在没有选中物品且不是拖动状态时,才不显示物品信息(根据需求,只在选中时显示)
// 注释掉显示物品信息的逻辑,只在选中时显示
/* const item = this.inventory.getItemAt(x, y);
if (item) {
this.showItemInfo(item);
} */
}
/**
* 单元格取消悬停事件
*/
onCellUnhovered() {
if (this.hoveredCell) {
// 恢复单元格颜色
const { x, y } = this.hoveredCell;
this.gridCells[y][x].setFillStyle(0x666666, 0.5);
this.hoveredCell = null;
}
// 如果有选中物品,不要隐藏物品信息
if (!this.selectedItem) {
// 隐藏物品信息
this.hideItemInfo();
}
}
/**
* 选择物品
* @param {Object} item - 要选择的物品
*/
selectItem(item) {
this.selectedItem = item;
// 高亮显示物品边框,不改变单元格颜色
const spriteObj = this.itemSprites.get(item.id);
if (spriteObj) {
spriteObj.border.setStrokeStyle(2, 0xffff00, 1); // 黄色边框表示选中
}
// 显示选中物品的详情
this.showItemInfo(item);
console.log('选中物品:', item.name);
// 如果是种子类型的物品,显示使用提示
if (item.type === 'seed') {
this.scene.events.emit('show-message', `右键点击、按Q键或点击[使用]按钮可以种植种子`);
}
}
/**
* 取消选择物品
*/
deselectItem() {
if (!this.selectedItem) return;
// 恢复物品边框颜色,不改变单元格颜色
const spriteObj = this.itemSprites.get(this.selectedItem.id);
if (spriteObj) {
spriteObj.border.setStrokeStyle(1, 0xffffff, 1); // 恢复白色边框
}
// 隐藏物品详情
this.hideItemInfo();
console.log('取消选择物品:', this.selectedItem.name);
this.selectedItem = null;
}
/**
* 显示物品信息
* @param {Object} item - 物品
*/
showItemInfo(item) {
// 创建物品信息面板
this.itemInfoPanel = this.scene.add.rectangle(0, 0, 200, 150, 0x000000, 0.8);
this.itemInfoPanel.setOrigin(0, 0);
this.itemInfoPanel.setStrokeStyle(1, 0xffffff);
this.itemInfoPanel.setPosition(
this.container.x + this.inventory.width * this.cellSize + 50,
this.container.y + this.inventory.height * this.cellSize + 20
);
// 设置足够高的深度,确保面板显示在最上层
this.itemInfoPanel.setDepth(150);
// 阻止事件冒泡,防止点击物品信息面板时触发角色移动
this.itemInfoPanel.setInteractive();
this.itemInfoPanel.on('pointerdown', (pointer) => {
return false; // 阻止事件冒泡
});
// 文本本身不需要交互,只需要面板阻止事件即可
// 如果需要文本也阻止事件,可以添加setInteractive和事件处理
this.itemInfoPanel.setScrollFactor(0); // 固定在屏幕上
// 添加物品信息文本
this.itemInfoText = this.scene.add.text(
this.itemInfoPanel.x + 10,
this.itemInfoPanel.y + 10,
`${item.name}\n${item.description}\n重量: ${item.weight}\n价值: ${item.value}`,
{ font: '12px Arial', fill: '#ffffff', wordWrap: { width: 180 } }
);
this.itemInfoText.setScrollFactor(0); // 固定在屏幕上
this.itemInfoText.setDepth(160); // 设置比面板更高的深度
// 添加"使用"按钮
const useButton = this.scene.add.text(
this.itemInfoPanel.x + 10,
this.itemInfoPanel.y + 90,
'[使用]',
{ font: '14px Arial', fill: '#00ff00' }
);
useButton.setInteractive({
useHandCursor: true
});
useButton.setDepth(170); // 设置比文本更高的深度
// 存储当前物品引用,确保回调函数中this指向正确
const currentItem = item;
const inventoryUI = this;
useButton.on('pointerdown', (pointer) => {
console.log('点击使用按钮,使用物品:', currentItem.name);
inventoryUI.useItem(currentItem);
return false; // 阻止事件冒泡
});
useButton.on('pointerover', (pointer) => {
useButton.setFill('#ffff00');
return false; // 阻止事件冒泡
});
useButton.on('pointerout', (pointer) => {
useButton.setFill('#00ff00');
return false; // 阻止事件冒泡
});
useButton.setScrollFactor(0); // 固定在屏幕上
// 如果是种子类型的物品,添加"种植/取消种植"按钮
// 如果是作物类型的物品,添加"制作种子"按钮
let actionButton = null;
let buttonX = this.itemInfoPanel.x + 80;
let buttonY = this.itemInfoPanel.y + 90;
if (item.type === 'seed') {
// 检查当前是否处于种植模式
const isPlantingMode = this.scene.isPlantingMode || false;
const buttonText = isPlantingMode ? '[取消种植]' : '[种植]';
const buttonColor = isPlantingMode ? '#ff0000' : '#00ff00';
actionButton = this.scene.add.text(
buttonX,
buttonY,
buttonText,
{ font: '14px Arial', fill: buttonColor }
);
// 设置足够高的深度,确保按钮可以点击
actionButton.setDepth(200);
actionButton.setScrollFactor(0); // 固定在屏幕上
actionButton.setInteractive({
useHandCursor: true,
draggable: false,
cursor: 'pointer'
});
// 确保事件监听正确绑定
actionButton.removeAllListeners();
actionButton.on('pointerdown', (pointer) => {
console.log('DEBUG: 种植/取消种植按钮点击事件触发');
if (isPlantingMode) {
// 如果是种植模式,调用取消种植
console.log('点击取消种植按钮,取消种植:', currentItem.name);
this.scene.cancelPlantingMode();
} else {
// 否则,使用种子开始种植
console.log('点击种植按钮,使用种子:', currentItem.name);
inventoryUI.useItem(currentItem);
}
return false; // 阻止事件冒泡
});
actionButton.on('pointerover', (pointer) => {
actionButton.setFill('#ffff00');
return false; // 阻止事件冒泡
});
actionButton.on('pointerout', (pointer) => {
actionButton.setFill(buttonColor);
return false; // 阻止事件冒泡
});
console.log('DEBUG: 种植/取消种植按钮创建完成,深度:', actionButton.depth);
} else if (item.type === 'food' && ['wheat', 'carrot'].includes(item.itemTypeId)) {
// 如果是作物类型的物品,添加"制作种子"按钮
const buttonText = '[制作种子]';
const buttonColor = '#0080ff';
actionButton = this.scene.add.text(
buttonX,
buttonY,
buttonText,
{ font: '14px Arial', fill: buttonColor }
);
// 设置足够高的深度,确保按钮可以点击
actionButton.setDepth(200);
actionButton.setScrollFactor(0); // 固定在屏幕上
actionButton.setInteractive({
useHandCursor: true,
draggable: false,
cursor: 'pointer'
});
// 确保事件监听正确绑定
actionButton.removeAllListeners();
actionButton.on('pointerdown', (pointer) => {
console.log('DEBUG: 制作种子按钮点击事件触发');
inventoryUI.craftSeeds(currentItem);
return false; // 阻止事件冒泡
});
actionButton.on('pointerover', (pointer) => {
actionButton.setFill('#ffff00');
return false; // 阻止事件冒泡
});
actionButton.on('pointerout', (pointer) => {
actionButton.setFill(buttonColor);
return false; // 阻止事件冒泡
});
console.log('DEBUG: 制作种子按钮创建完成,深度:', actionButton.depth);
}
// 存储按钮引用,以便后续销毁
this.itemInfoButton = useButton;
this.plantButton = actionButton;
this.container.add(this.itemInfoPanel);
this.container.add(this.itemInfoText);
this.container.add(useButton);
// 如果有额外按钮(种植/制作种子),添加到容器中
if (actionButton) {
this.container.add(actionButton);
}
// 添加拾取按钮
const dropButton = this.scene.add.text(
this.itemInfoPanel.x + 10,
this.itemInfoPanel.y + 115,
'[丢弃]',
{ font: '14px Arial', fill: '#ff0000' }
);
dropButton.setInteractive({
useHandCursor: true
});
dropButton.setDepth(170); // 设置比文本更高的深度
dropButton.on('pointerdown', (pointer) => {
console.log('点击丢弃按钮,丢弃物品:', currentItem.name);
inventoryUI.dropItem(currentItem);
return false; // 阻止事件冒泡
});
dropButton.on('pointerover', (pointer) => {
dropButton.setFill('#ffff00');
return false; // 阻止事件冒泡
});
dropButton.on('pointerout', (pointer) => {
dropButton.setFill('#ff0000');
return false; // 阻止事件冒泡
});
dropButton.setScrollFactor(0); // 固定在屏幕上
this.container.add(dropButton);
// 存储拾取按钮引用,以便后续销毁
this.dropButton = dropButton;
}
/**
* 更新种植按钮状态
* @param {boolean} isPlanting - 是否处于种植模式
*/
updatePlantButtonState(isPlanting) {
// 如果有显示的物品信息且是种子类型,更新按钮状态
if (this.itemInfoPanel && this.plantButton) {
console.log('DEBUG: updatePlantButtonState 方法被调用,isPlanting:', isPlanting);
// 设置足够高的深度,确保按钮可以点击
this.plantButton.setDepth(200);
// 确保按钮可见
this.plantButton.setVisible(true);
// 更新按钮文本和颜色
this.plantButton.setText(isPlanting ? '[取消种植]' : '[种植]');
this.plantButton.setFill(isPlanting ? '#ff0000' : '#00ff00');
// 重新绑定点击事件
const currentItem = this.selectedItem;
const inventoryUI = this;
// 移除旧的事件监听器
this.plantButton.removeAllListeners();
// 确保按钮可以交互
this.plantButton.setInteractive({
useHandCursor: true,
draggable: false,
cursor: 'pointer'
});
// 重新添加事件监听器
this.plantButton.on('pointerdown', (pointer) => {
console.log('DEBUG: 更新后的种植/取消种植按钮点击事件触发');
if (isPlanting) {
// 如果是种植模式,调用取消种植
console.log('点击取消种植按钮,取消种植:', currentItem.name);
inventoryUI.scene.cancelPlantingMode();
} else {
// 否则,使用种子开始种植
console.log('点击种植按钮,使用种子:', currentItem.name);
inventoryUI.useItem(currentItem);
}
return false; // 阻止事件冒泡
});
this.plantButton.on('pointerover', (pointer) => {
this.plantButton.setFill('#ffff00');
return false; // 阻止事件冒泡
});
this.plantButton.on('pointerout', (pointer) => {
this.plantButton.setFill(isPlanting ? '#ff0000' : '#00ff00');
return false; // 阻止事件冒泡
});
console.log('DEBUG: 种植/取消种植按钮状态更新完成');
}
}
/**
* 隐藏物品信息
*/
hideItemInfo() {
if (this.itemInfoPanel) {
this.itemInfoPanel.destroy();
this.itemInfoText.destroy();
if (this.itemInfoButton) {
this.itemInfoButton.destroy();
this.itemInfoButton = null;
}
if (this.plantButton) {
this.plantButton.destroy();
this.plantButton = null;
}
if (this.dropButton) {
this.dropButton.destroy();
this.dropButton = null;
}
this.itemInfoPanel = null;
this.itemInfoText = null;
}
}
/**
* 丢弃物品
* @param {Object} item - 要丢弃的物品
*/
dropItem(item) {
console.log('dropItem:', item.name, 'ID:', item.id);
// 从背包中移除物品
const removedItem = this.inventory.removeItem(item.id);
if (!removedItem) {
console.log('无法从背包中移除物品:', item.name);
return;
}
// 获取物品ID和基本信息
const itemId = removedItem.itemTypeId || removedItem.id;
// 在角色位置创建该物品
if (this.scene.itemManager) {
const player = this.scene.player;
this.scene.itemManager.createItem(itemId, player.x, player.y);
console.log('已在角色位置创建丢弃的物品:', removedItem.name);
}
// 更新UI显示
this.updateUI();
// 显示丢弃成功消息
this.scene.events.emit('show-message', `已丢弃 ${removedItem.name}`);
// 取消选择物品
this.deselectItem();
}
/**
* 更新UI显示
*/
updateUI() {
// 移除所有物品精灵和边框
this.itemSprites.forEach(spriteObj => {
spriteObj.sprite.destroy();
spriteObj.border.destroy();
});
this.itemSprites.clear();
// 重新添加所有物品精灵
const items = this.inventory.getAllItems();
if (items instanceof Map) {
// 如果是Map对象,使用Map的forEach方法
items.forEach(item => {
this.addItemSprite(item);
});
} else {
// 如果是数组,使用数组的forEach方法
items.forEach(item => {
this.addItemSprite(item);
});
}
// 更新统计信息
this.updateStats();
}
/**
* 添加物品精灵(基于物品中心坐标)
* @param {Object} item - 物品
*/
addItemSprite(item) {
// 获取物品中心坐标和尺寸
const { x: centerX, y: centerY } = item.position;
const { width, height } = item.gridSize;
// 计算左上角坐标
const topLeftX = Math.floor(centerX - (width - 1) / 2);
const topLeftY = Math.floor(centerY - (height - 1) / 2);
// 计算精灵位置和大小
const spriteX = 10 + topLeftX * this.cellSize;
const spriteY = 10 + topLeftY * this.cellSize;
const spriteWidth = width * this.cellSize;
const spriteHeight = height * this.cellSize;
// 创建精灵 - 使用物品类型ID而不是唯一ID,因为纹理是用物品类型ID创建的
const sprite = this.scene.add.sprite(spriteX, spriteY, item.itemTypeId || item.id);
sprite.setOrigin(0, 0);
sprite.setDisplaySize(spriteWidth, spriteHeight);
sprite.setScrollFactor(0); // 固定在屏幕上
sprite.setDepth(1); // 确保精灵在单元格之上
// 添加边框
const border = this.scene.add.rectangle(spriteX, spriteY, spriteWidth, spriteHeight, 0xffffff, 0);
border.setOrigin(0, 0);
border.setStrokeStyle(1, 0xffffff);
border.setScrollFactor(0); // 固定在屏幕上
border.setDepth(2); // 确保边框在精灵之上
// 处理物品精灵的点击事件
sprite.setInteractive();
sprite.on('pointerdown', (pointer) => {
this.onItemSpriteDown(item, pointer);
return false; // 阻止事件冒泡
});
border.setInteractive();
border.on('pointerdown', (pointer) => {
this.onItemSpriteDown(item, pointer);
return false; // 阻止事件冒泡
});
this.container.add(sprite);
this.container.add(border);
this.itemSprites.set(item.id, { sprite, border });
}
/**
* 显示背包
*/
show() {
this.container.setVisible(true);
this.isOpen = true;
this.updateUI();
}
/**
* 隐藏背包
*/
hide() {
this.container.setVisible(false);
this.isOpen = false;
this.deselectItem();
this.hideItemInfo();
}
/**
* 切换背包显示
*/
toggle() {
if (this.isOpen) {
this.hide();
} else {
this.show();
}
}
/**
* 添加物品到背包并更新UI
* @param {Object} item - 要添加的物品
* @returns {boolean} 是否添加成功
*/
addItem(item) {
const success = this.inventory.addItem(item);
if (success) {
this.updateUI();
}
return success;
}
/**
* 从背包中移除物品并更新UI
* @param {string} itemId - 物品ID
* @returns {Object|null} 移除的物品
*/
removeItem(itemId) {
const item = this.inventory.removeItem(itemId);
if (item) {
this.updateUI();
}
return item;
}
/**
* 制作种子
* @param {Object} item - 要制作种子的作物
*/
craftSeeds(item) {
console.log('craftSeeds:', item.name, 'ID:', item.id);
// 检查物品是否可以制作种子
if (item.type !== 'food' || !['wheat', 'carrot'].includes(item.itemTypeId)) {
console.log('该物品不能制作种子:', item.name);
return;
}
// 从背包中移除作物
const removedItem = this.inventory.removeItem(item.id);
if (!removedItem) {
console.log('无法从背包中移除作物:', item.name);
return;
}
// 制作种子数量(1个作物制作2个种子)
const seedsCount = 2;
// 获取对应作物的种子ID
const seedId = `${item.itemTypeId}_seed`;
// 使用ItemManager创建种子物品
if (this.scene.itemManager) {
let successfullyAdded = 0;
let seedsToDrop = [];
// 先创建所有种子
for (let i = 0; i < seedsCount; i++) {
// 创建种子物品
const seedItem = this.scene.itemManager.createItem(seedId, 0, 0);
if (seedItem) {
// 尝试将种子添加到背包
const success = this.inventory.addItem(seedItem);
if (success) {
successfullyAdded++;
} else {
// 如果背包空间不足,将种子添加到待丢弃列表
seedsToDrop.push(seedItem);
}
}
}
// 如果背包空间不足,将无法放入背包的种子放到地图上
if (seedsToDrop.length > 0 && this.scene.player) {
const player = this.scene.player;
seedsToDrop.forEach(seedItem => {
// 设置种子位置为玩家位置
seedItem.x = player.x;
seedItem.y = player.y;
// 确保种子被正确添加到场景中
this.scene.add.existing(seedItem);
console.log('背包空间不足,已将种子放到地图上:', seedItem.name);
});
}
// 更新UI显示
this.updateUI();
// 显示制作成功消息
let message = `成功制作了${successfullyAdded}个${seedId.replace('_seed', '')}种子`;
if (seedsToDrop.length > 0) {
message += `,${seedsToDrop.length}个种子因背包空间不足已放到地上`;
}
this.scene.events.emit('show-message', message);
console.log(`成功制作了${successfullyAdded}个${seedId.replace('_seed', '')}种子,${seedsToDrop.length}个种子放到了地上`);
} else {
console.log('场景中没有ItemManager,无法制作种子');
// 如果无法制作种子,将作物归还
this.inventory.addItem(item);
}
}
/**
* 销毁背包UI
*/
destroy() {
this.container.destroy();
}
}