// 背包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(); } }