// 物品系统测试场景 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'; export default class ItemTestScene extends Phaser.Scene { constructor() { super({ key: 'ItemTestScene' }); } 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.cameras.main.centerOn(0, 0); // 初始化系统 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(); // 创建玩家纹理 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); } // 创建一个测试单位 const unit = new Unit(this, 0, 0, 'player'); // 为单位添加一些属性,用于测试物品效果 unit.name = '测试单位'; unit.health = 100; unit.nutrition = 50; unit.hydration = 50; unit.equipWeapon = function(weapon) { this.weapon = weapon; console.log(`${this.name} 装备了 ${weapon.name}`); }; this.unitGroup.add(unit); // 自动选中单位 this.events.emit('select-unit', unit); // 添加碰撞检测 this.physics.add.collider(this.unitGroup, this.unitGroup); // 初始化物品管理器 this.itemManager = new ItemManager(this); // 当物品数据加载完成后创建初始物品 this.itemManager.onDataLoaded(() => { this.createInitialItems(); }); // 创建侧边栏UI(先创建,确保它在最底层) this.createSidebar(); // 添加场景说明文本 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, '点击物品查看信息,右键移动到物品位置', { 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 spaceText = this.add.text(10, 220, '按空格键返回启动场景', { fontSize: '16px', fill: '#ffffff' }); spaceText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 spaceText.setDepth(10); // 设置深度,确保显示在侧边栏上方 // 显示单位状态 this.updateUnitStatus(unit); // 显示默认提示 this.itemInfoText.setText('未选择任何物品'); this.interactionText.setText('点击物品查看详细信息,交互范围50像素'); this.generalInfoText.setText('欢迎使用物品系统测试场景'); // 添加场景提示信息 const interactionHintText = this.add.text(10, 250, '点击物品查看详细信息,交互范围50像素', { fontSize: '16px', fill: '#ffffff' }); interactionHintText.setScrollFactor(0, 0); // 固定在屏幕上,不随相机移动 interactionHintText.setDepth(10); // 设置深度,确保显示在侧边栏上方 // 注册键盘事件 this.input.keyboard.on('keydown-ONE', () => { this.itemManager.createRandomItem(); }); this.input.keyboard.on('keydown-TWO', () => { // 在单位附近创建食物类物品 const x = unit.x + Phaser.Math.Between(-100, 100); const y = unit.y + Phaser.Math.Between(-100, 100); this.itemManager.createItemByType('food', x, y); }); this.input.keyboard.on('keydown-THREE', () => { // 在单位附近创建工具类物品 const x = unit.x + Phaser.Math.Between(-100, 100); const y = unit.y + Phaser.Math.Between(-100, 100); this.itemManager.createItemByType('tool', x, y); }); this.input.keyboard.on('keydown-FOUR', () => { this.itemManager.clearAllItems(); this.itemInfoText.setText('所有物品已清理'); }); this.input.keyboard.on('keydown-SPACE', () => { this.scene.start('BootScene'); }); // 监听物品点击事件 this.events.on('item-clicked', (item) => { this.showItemInfo(item); }); // 创建一些交互按钮 this.createButtons(); } /** * 创建初始物品 */ createInitialItems() { // 在不同位置创建各种类型的物品 const itemTypes = ['food', 'tool', 'medical', 'weapon']; const unit = this.unitGroup.getFirstAlive(); for (let i = 0; i < itemTypes.length; i++) { const x = unit.x + (i - 2) * 200; const y = unit.y - 200; this.itemManager.createItemByType(itemTypes[i], x, y); } } /** * 创建交互按钮 */ 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('所有物品已清理'); }); } /** * 创建按钮 * @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.unitGroup.getFirstAlive(); 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 += `距离: ${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); this.interactionText.setText(''); this.itemInfoText.setText('未选择任何物品'); }); // 注册Q键快捷使用物品 this.input.keyboard.once('keydown-Q', () => { item.use(unit); this.interactionText.setText(''); this.itemInfoText.setText('未选择任何物品'); }); } else { this.interactionText.setText('距离太远,无法交互'); } // 移除5秒后自动清除的逻辑,让信息保持显示 } /** * 创建侧边栏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); } update() { this.inputSystem.update(); // 更新所有单位 this.unitGroup.getChildren().forEach(unit => { if (unit.update) { unit.update(); } unit.updateMovement(); // 更新单位状态显示 this.updateUnitStatus(unit); }); } }