// 物品列表菜单测试场景 import Unit from '../objects/Unit.js'; import { InputSystem } from '../systems/InputSystem.js'; import { SelectionSystem } from '../systems/SelectionSystem.js'; import { CommandSystem } from '../systems/CommandSystem.js'; import { ItemManager } from '../items/ItemManager.js'; import { Inventory } from '../items/Inventory.js'; import { InventoryUI } from '../ui/InventoryUI.js'; import { ItemListUI } from '../ui/ItemListUI.js'; export default class ItemListTestScene extends Phaser.Scene { constructor() { super({ key: 'ItemListTestScene' }); } preload() { // 加载物品数据 this.load.json('items', './data/items.json'); } create() { // 物理世界和相机边界 const worldSize = 1000; this.physics.world.setBounds(-worldSize, -worldSize, worldSize * 2, worldSize * 2); this.cameras.main.setBounds(-worldSize, -worldSize, worldSize * 2, worldSize * 2); // 初始化系统 this.inputSystem = new InputSystem(this, { keyboard: true, mouse: true, joystick: false, selection: true }); this.selectionSystem = new SelectionSystem(this); this.commandSystem = new CommandSystem(this); // 创建单位组 this.unitGroup = this.add.group(); // 创建背景 this.createBackground(); // 创建玩家 this.createPlayer(); // 初始化物品管理器 this.itemManager = new ItemManager(this); // 初始化背包系统 this.initInventory(); // 创建物品列表UI this.initItemListUI(); // 创建测试物品 this.createTestItems(); // 设置输入处理 this.setupInput(); // 创建侧边栏UI this.createSidebar(); // 显示提示信息 this.showInstructions(); // 显示单位状态 this.updateUnitStatus(this.player); // 显示默认提示 this.itemInfoText.setText('未选择任何物品'); this.interactionText.setText('按c键打开物品列表菜单'); this.generalInfoText.setText('欢迎使用物品列表菜单测试场景'); } /** * 创建背景 */ createBackground() { // 创建纯色背景 this.add.rectangle(0, 0, this.sys.game.config.width, this.sys.game.config.height, 0x1a1a2e); } /** * 创建玩家 */ createPlayer() { // 为玩家创建纯色纹理 if (!this.textures.exists('player')) { const canvas = document.createElement('canvas'); canvas.width = 32; canvas.height = 32; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#4a90e2'; ctx.beginPath(); ctx.arc(16, 16, 16, 0, Math.PI * 2); ctx.fill(); this.textures.addCanvas('player', canvas); } // 创建玩家单位 this.player = new Unit(this, 0, 0, 'player'); // 设置玩家属性 this.player.name = '测试玩家'; this.player.health = 100; this.player.nutrition = 100; this.player.hydration = 100; this.player.equipWeapon = function(weapon) { this.weapon = weapon; console.log(`${this.name} 装备了 ${weapon.name}`); }; // 添加到单位组 this.unitGroup.add(this.player); // 自动选中玩家 this.events.emit('select-unit', this.player); // 添加碰撞检测 this.physics.add.collider(this.unitGroup, this.unitGroup); // 保持相机中心在世界原点,与背包测试场景一致 this.cameras.main.centerOn(0, 0); } /** * 初始化背包系统 */ initInventory() { // 创建背包(6x4网格) this.player.inventory = new Inventory(6, 4); // 创建背包UI(会自动固定在右侧) this.inventoryUI = new InventoryUI(this, this.player.inventory, 40); } /** * 初始化物品列表UI */ initItemListUI() { // 创建物品列表UI,位于屏幕左下角 const x = 10; const y = this.sys.game.config.height - 350; this.itemListUI = new ItemListUI(this, x, y); } /** * 创建测试物品 */ createTestItems() { // 等待物品数据加载完成 this.itemManager.onDataLoaded(() => { // 创建初始物品 this.createInitialItems(); // 绑定物品点击事件 this.events.on('item-clicked', (item) => { this.showItemInfo(item); }); }); } /** * 创建初始物品 */ createInitialItems() { // 在不同位置创建各种类型的物品,确保有些在交互范围内,有些在范围外 const itemTypes = ['food', 'tool', 'medical', 'weapon']; // 在交互范围内创建物品(距离玩家50像素内) for (let i = 0; i < itemTypes.length; i++) { const x = this.player.x + (i - 2) * 40; const y = this.player.y - 40; this.itemManager.createItemByType(itemTypes[i], x, y); } // 在交互范围外创建物品(距离玩家100像素外) for (let i = 0; i < itemTypes.length; i++) { const x = this.player.x + (i - 2) * 120; const y = this.player.y - 120; this.itemManager.createItemByType(itemTypes[i], x, y); } // 在场景中随机位置创建更多物品 for (let i = 0; i < 8; i++) { const itemIds = ['water_bottle', 'canned_food', 'crowbar', 'first_aid_kit', 'flashlight', 'knife']; const randomItemId = itemIds[Math.floor(Math.random() * itemIds.length)]; const x = this.player.x + Phaser.Math.Between(-300, 300); const y = this.player.y + Phaser.Math.Between(-300, 300); this.itemManager.createItem(randomItemId, x, y); } } /** * 设置输入处理 */ setupInput() { // 键盘输入 this.cursors = this.input.keyboard.createCursorKeys(); // 背包快捷键(B键) this.input.keyboard.on('keydown-B', () => { this.inventoryUI.toggle(); }); // 物品列表菜单快捷键(C键) this.input.keyboard.on('keydown-C', () => { this.itemListUI.toggle(); }); // 注册键盘事件 this.input.keyboard.on('keydown-ONE', () => { this.itemManager.createRandomItem(); }); this.input.keyboard.on('keydown-TWO', () => { // 在单位附近创建食物类物品 const x = this.player.x + Phaser.Math.Between(-100, 100); const y = this.player.y + Phaser.Math.Between(-100, 100); this.itemManager.createItemByType('food', x, y); }); this.input.keyboard.on('keydown-THREE', () => { // 在单位附近创建工具类物品 const x = this.player.x + Phaser.Math.Between(-100, 100); const y = this.player.y + Phaser.Math.Between(-100, 100); this.itemManager.createItemByType('tool', x, y); }); this.input.keyboard.on('keydown-FOUR', () => { this.itemManager.clearAllItems(); this.itemInfoText.setText('所有物品已清理'); // 更新物品列表UI if (this.itemListUI.visible) { this.itemListUI.updateItems(this.player, this.itemManager.getActiveItems()); } }); this.input.keyboard.on('keydown-SPACE', () => { this.scene.start('BootScene'); }); // 创建交互按钮 this.createButtons(); } /** * 创建交互按钮 */ createButtons() { const buttonWidth = 200; const buttonHeight = 40; const buttonY = this.sys.game.config.height - 100; // 创建随机物品按钮 this.createButton(this.sys.game.config.width - buttonWidth - 10, buttonY, '创建随机物品', () => { this.itemManager.createRandomItem(); }); // 创建清理物品按钮 this.createButton(this.sys.game.config.width - buttonWidth - 10, buttonY + 50, '清理所有物品', () => { this.itemManager.clearAllItems(); this.itemInfoText.setText('所有物品已清理'); // 更新物品列表UI if (this.itemListUI.visible) { this.itemListUI.updateItems(this.player, this.itemManager.getActiveItems()); } }); } /** * 创建按钮 * @param {number} x - 按钮x坐标 * @param {number} y - 按钮y坐标 * @param {string} text - 按钮文本 * @param {function} callback - 点击回调函数 */ createButton(x, y, text, callback) { // 创建按钮背景 const button = this.add.rectangle(x, y, 200, 40, 0x333333); button.setOrigin(0.5, 0.5); button.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 button.setDepth(15); // 设置深度,确保显示在场景说明文本上方 // 创建按钮文本 const buttonText = this.add.text(x, y, text, { fontSize: '16px', fill: '#ffffff', fontFamily: 'Arial' }); buttonText.setOrigin(0.5, 0.5); buttonText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 buttonText.setDepth(16); // 设置深度,确保显示在按钮背景上方 // 设置按钮交互 button.setInteractive({ useHandCursor: true }); // 按钮事件 button.on('pointerdown', callback); button.on('pointerover', () => { button.setFillStyle(0x555555); }); button.on('pointerout', () => { button.setFillStyle(0x333333); }); } /** * 显示物品信息 * @param {Item} item - 物品实例 */ showItemInfo(item) { const unit = this.player; const isInRange = item.isInInteractionRange(unit); const info = item.getInfo(); let infoText = `${info.name}\n`; infoText += `${info.description}\n`; infoText += `类型: ${info.type}\n`; infoText += `重量: ${info.weight}kg\n`; infoText += `体积: ${info.volume}L\n`; infoText += `价值: ${info.value}金币\n`; infoText += `尺寸: ${info.gridSize.width}x${info.gridSize.height}\n`; infoText += `距离: ${Math.round(Math.sqrt(Math.pow(item.x - unit.x, 2) + Math.pow(item.y - unit.y, 2)))}m\n`; // 显示物品属性 infoText += '属性: '; const properties = []; for (const [key, value] of Object.entries(info.properties)) { properties.push(`${key}: ${value}`); } infoText += properties.join(', '); this.itemInfoText.setText(infoText); // 显示交互提示 if (isInRange) { this.interactionText.setText('按E键拾取物品,按Q键快捷使用'); // 注册E键拾取物品 this.input.keyboard.once('keydown-E', () => { item.pickup(unit); // 物品拾取后,更新物品列表UI if (this.itemListUI.visible) { this.itemListUI.updateItems(this.player, this.itemManager.getActiveItems()); } this.interactionText.setText(''); this.itemInfoText.setText('未选择任何物品'); }); // 注册Q键快捷使用物品 this.input.keyboard.once('keydown-Q', () => { item.use(unit); // 更新物品列表UI if (this.itemListUI.visible) { this.itemListUI.updateItems(this.player, this.itemManager.getActiveItems()); } this.interactionText.setText(''); this.itemInfoText.setText('未选择任何物品'); }); } else { this.interactionText.setText('距离太远,无法交互'); } } /** * 显示提示信息 */ showInstructions() { const titleText = this.add.text(10, 10, '物品列表菜单测试场景', { fontSize: '20px', fill: '#ffffff' }); titleText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 titleText.setDepth(10); // 设置深度,确保显示在侧边栏上方 const moveText = this.add.text(10, 40, 'WASD或方向键移动单位,左键点击选择单位', { fontSize: '16px', fill: '#ffffff' }); moveText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 moveText.setDepth(10); // 设置深度,确保显示在侧边栏上方 const itemText = this.add.text(10, 70, '点击物品查看详细信息,交互范围50像素', { fontSize: '16px', fill: '#ffffff' }); itemText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 itemText.setDepth(10); // 设置深度,确保显示在侧边栏上方 const key1Text = this.add.text(10, 100, '按1键:创建随机物品', { fontSize: '16px', fill: '#ffffff' }); key1Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 key1Text.setDepth(10); // 设置深度,确保显示在侧边栏上方 const key2Text = this.add.text(10, 130, '按2键:创建食物类物品', { fontSize: '16px', fill: '#ffffff' }); key2Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 key2Text.setDepth(10); // 设置深度,确保显示在侧边栏上方 const key3Text = this.add.text(10, 160, '按3键:创建工具类物品', { fontSize: '16px', fill: '#ffffff' }); key3Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 key3Text.setDepth(10); // 设置深度,确保显示在侧边栏上方 const key4Text = this.add.text(10, 190, '按4键:清理所有物品', { fontSize: '16px', fill: '#ffffff' }); key4Text.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 key4Text.setDepth(10); // 设置深度,确保显示在侧边栏上方 const keyBText = this.add.text(10, 220, '按B键:打开/关闭背包', { fontSize: '16px', fill: '#ffffff' }); keyBText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 keyBText.setDepth(10); // 设置深度,确保显示在侧边栏上方 const keyCText = this.add.text(10, 250, '按C键:打开/关闭物品列表菜单', { fontSize: '16px', fill: '#ffff00' }); keyCText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 keyCText.setDepth(10); // 设置深度,确保显示在侧边栏上方 const spaceText = this.add.text(10, 280, '按空格键返回启动场景', { fontSize: '16px', fill: '#ffffff' }); spaceText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 spaceText.setDepth(10); // 设置深度,确保显示在侧边栏上方 } /** * 创建侧边栏UI */ createSidebar() { // 侧边栏宽度 const sidebarWidth = 300; const sidebarDepth = 5; // 侧边栏深度值,确保显示在游戏元素上方,但低于场景说明文本 // 创建侧边栏背景 this.sidebar = this.add.rectangle( this.sys.game.config.width - sidebarWidth, 0, sidebarWidth, this.sys.game.config.height, 0x111111, 0.9 ); this.sidebar.setOrigin(0, 0); this.sidebar.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.sidebar.setDepth(sidebarDepth); // 设置深度,确保显示在游戏元素上方 // 添加侧边栏边框 this.sidebarBorder = this.add.rectangle( this.sys.game.config.width - sidebarWidth, 0, sidebarWidth, this.sys.game.config.height, 0x444444, 0 ); this.sidebarBorder.setOrigin(0, 0); this.sidebarBorder.setStrokeStyle(2, 0x444444, 1); this.sidebarBorder.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.sidebarBorder.setDepth(sidebarDepth + 1); // 设置深度,确保显示在侧边栏背景上方 // 侧边栏标题 const title = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 20, '游戏信息面板', { fontSize: '20px', fill: '#ffffff', fontWeight: 'bold' } ); title.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 title.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 // 通用信息区域标题 const generalTitle = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 50, '通用信息:', { fontSize: '16px', fill: '#4CAF50', fontWeight: 'bold' } ); generalTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 generalTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 this.generalInfoText = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 75, '', { fontSize: '14px', fill: '#ffffff', wordWrap: { width: sidebarWidth - 40 } } ); this.generalInfoText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.generalInfoText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 // 角色属性区域标题 const characterTitle = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 120, '角色属性:', { fontSize: '16px', fill: '#2196F3', fontWeight: 'bold' } ); characterTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 characterTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 this.unitStatusText = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 145, '', { fontSize: '14px', fill: '#ffffff', wordWrap: { width: sidebarWidth - 40 } } ); this.unitStatusText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.unitStatusText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 // 交互提示区域标题 const interactionTitle = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 220, '交互提示:', { fontSize: '16px', fill: '#FFEB3B', fontWeight: 'bold' } ); interactionTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 interactionTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 this.interactionText = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 245, '', { fontSize: '14px', fill: '#ffff00', wordWrap: { width: sidebarWidth - 40 } } ); this.interactionText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.interactionText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 // 物品详情区域标题 const itemTitle = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 350, '物品详情:', { fontSize: '16px', fill: '#FF9800', fontWeight: 'bold' } ); itemTitle.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 itemTitle.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 this.itemInfoText = this.add.text( this.sys.game.config.width - sidebarWidth + 20, 375, '', { fontSize: '14px', fill: '#ffffff', wordWrap: { width: sidebarWidth - 40 } } ); this.itemInfoText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 this.itemInfoText.setDepth(sidebarDepth + 2); // 设置深度,确保显示在侧边栏边框上方 } /** * 更新单位状态显示 * @param {Unit} unit - 单位实例 */ updateUnitStatus(unit) { let statusText = `${unit.name} 状态:\n`; statusText += `生命值: ${unit.health}\n`; statusText += `营养值: ${unit.nutrition}\n`; statusText += `水分值: ${unit.hydration}\n`; if (unit.weapon) { statusText += `武器: ${unit.weapon.name}`; } this.unitStatusText.setText(statusText); } /** * 显示消息 * @param {string} message - 消息内容 */ showMessage(message) { // 创建消息 const messageText = this.add.text( this.player.x, this.player.y - 50, message, { font: '20px Arial', fill: '#ffffff', backgroundColor: '#000000', padding: { x: 10, y: 5 } } ); messageText.setOrigin(0.5, 0.5); messageText.setDepth(20); messageText.setScrollFactor(1); // 允许消息随相机移动 // 3秒后自动移除消息 this.time.delayedCall(3000, () => { if (messageText) { messageText.destroy(); } }); } update() { this.inputSystem.update(); // 更新物品列表UI(如果可见) this.itemListUI.update(); // 更新所有单位 this.unitGroup.getChildren().forEach(unit => { if (unit.update) { unit.update(); } unit.updateMovement(); // 更新单位状态显示 this.updateUnitStatus(unit); }); } }