diff --git a/main.js b/main.js index e797c0f..020a2bf 100644 --- a/main.js +++ b/main.js @@ -42,6 +42,11 @@ import MenuScene from './scenes/MenuScene.js'; import TmpScene from './scenes/TmpScene.js'; // 导入测试对象场景 import TestObjectsScene from './scenes/testScenes/TestObjectsScene.js'; +// 导入角色类测试场景 +import CharacterClassTestScene from './scenes/testScenes/CharacterClassTestScene.js'; +// 导入武器测试场景 +import WeaponTestScene from './scenes/testScenes/WeaponTestScene.js'; + // 创建游戏的最终配置对象 const config = { // 使用扩展运算符(...)将gameConfig中的所有配置项复制到当前对象中 @@ -51,6 +56,8 @@ const config = { scene: [ MenuScene, TmpScene, + WeaponTestScene, + CharacterClassTestScene, TestObjectsScene, BootScene, GameScene, diff --git a/objects/Character.js b/objects/Character.js new file mode 100644 index 0000000..b4420b2 --- /dev/null +++ b/objects/Character.js @@ -0,0 +1,386 @@ +// objects/Character.js +// 角色类,包含属性、动画、技能等系统 +export default class Character extends Phaser.Physics.Arcade.Sprite { + constructor(scene, x, y, config) { + super(scene, x, y, config.texture || 'player0-0'); + scene.add.existing(this); + scene.physics.add.existing(this); + + // 配置 + this.config = config; + + // 设置角色原点为底部中点 + this.setOrigin(0.5, 1); + + // 设置角色深度,确保显示在指示器上方 + this.setDepth(10); + + // 启用圆形碰撞体 + this.setCircle(config.collisionRadius || 14); + + // 启用与世界边界的碰撞 + this.setCollideWorldBounds(true); + + // 初始化系统 + this.initSystems(); + + // 初始化状态 + this.state = { + isMoving: false, + isSelected: false, + currentSkill: null, + isCasting: false + }; + + // 移动控制 + this.target = null; + this.canMove = true; + } + + /** + * 初始化系统 + */ + initSystems() { + // 属性系统 + this.initAttributes(); + + // 动画系统 + this.initAnimationSystem(); + + // 技能系统 + this.initSkillSystem(); + + // 指示器系统 + this.initIndicatorSystem(); + } + + /** + * 初始化属性系统 + */ + initAttributes() { + this.attributes = { + health: this.config.health || 100, + maxHealth: this.config.health || 100, + mana: this.config.mana || 50, + maxMana: this.config.mana || 50, + speed: this.config.speed || 150, + attack: this.config.attack || 20, + defense: this.config.defense || 10 + }; + } + + /** + * 初始化动画系统 + */ + initAnimationSystem() { + this.animationSystem = { + currentAnimation: null, + animations: this.config.animations || {}, + playAnimation: (key) => { + if (!this.anims.isPlaying || this.anims.currentAnim.key !== key) { + this.play(key); + this.animationSystem.currentAnimation = key; + } + }, + stopAnimation: () => { + this.anims.stop(); + this.animationSystem.currentAnimation = null; + } + }; + } + + /** + * 初始化技能系统 + */ + initSkillSystem() { + this.skills = this.config.skills || []; + this.cooldowns = {}; + } + + /** + * 初始化指示器系统 + */ + initIndicatorSystem() { + // 选中指示器 + this.selectedIndicator = this.scene.add.circle(this.x, this.y, this.width * 1.5, 0x00ff00, 0.0); + this.selectedIndicator.setStrokeStyle(2, 0x00ff00, 1); + this.selectedIndicator.setVisible(false); + this.selectedIndicator.setOrigin(0.5, 0.5); + this.selectedIndicator.setScrollFactor(1, 1); + this.selectedIndicator.setDepth(5); + + // 目标指示器 + this.targetIndicator = null; + + // 路径图形 + this.pathGraphics = null; + } + + /** + * 设置选中状态 + * @param {boolean} isSelected + */ + setSelected(isSelected) { + this.state.isSelected = isSelected; + if (this.selectedIndicator) { + this.selectedIndicator.setVisible(isSelected); + } + } + + /** + * 设置移动目标 + * @param {number} x + * @param {number} y + */ + setTarget(x, y) { + // 获取世界边界 + const worldBounds = this.scene.physics.world.bounds; + + // 限制目标点在世界边界内 + const clampedX = Math.max(worldBounds.x, Math.min(worldBounds.right, x)); + const clampedY = Math.max(worldBounds.y, Math.min(worldBounds.bottom, y)); + + this.target = { x: clampedX, y: clampedY }; + + // 创建目标指示器 + if (!this.targetIndicator) { + this.targetIndicator = this.scene.add.circle(0, 0, 8, 0xff0000, 1); + this.targetIndicator.setOrigin(0.5, 0.5); + this.targetIndicator.setScrollFactor(1, 1); + this.targetIndicator.setDepth(5); + } + + // 更新目标指示器位置 + this.targetIndicator.setPosition(this.target.x, this.target.y); + this.targetIndicator.setVisible(this.state.isSelected); + + // 创建路径图形 + if (!this.pathGraphics) { + this.pathGraphics = this.scene.add.graphics(); + this.pathGraphics.setScrollFactor(1, 1); + this.pathGraphics.setDepth(5); + } + } + + /** + * 清除目标 + */ + clearTarget() { + this.target = null; + this.setVelocity(0, 0); + + // 隐藏目标指示器 + if (this.targetIndicator) { + this.targetIndicator.setVisible(false); + } + + // 清除路径 + if (this.pathGraphics) { + this.pathGraphics.clear(); + } + } + + /** + * 相对移动控制 + * @param {number} x + * @param {number} y + */ + moveRelative(x, y) { + if (!this.canMove) { + this.setVelocity(0, 0); + return; + } + + const speed = this.attributes.speed; + const magnitude = Math.sqrt(x * x + y * y); + + if (magnitude > 0) { + this.clearTarget(); + this.state.isMoving = true; + const normalizedX = x / magnitude; + const normalizedY = y / magnitude; + this.setVelocity(normalizedX * speed, normalizedY * speed); + + // 处理朝向 + if (normalizedX < -0.1) { + this.setFlipX(true); + } else if (normalizedX > 0.1) { + this.setFlipX(false); + } + + // 播放移动动画 + this.animationSystem.playAnimation(this.config.moveAnimation || 'player0-move'); + } else { + this.setVelocity(0, 0); + this.state.isMoving = false; + + // 停止动画,显示静止帧 + this.animationSystem.stopAnimation(); + this.setTexture(this.config.idleTexture || 'player0-0'); + } + } + + /** + * 施放技能 + * @param {string} skillId + */ + castSkill(skillId) { + const skill = this.skills.find(s => s.id === skillId); + if (!skill) return false; + + // 检查冷却 + if (this.cooldowns[skillId] && this.cooldowns[skillId] > this.scene.time.now) { + return false; + } + + // 检查 mana + if (this.attributes.mana < skill.cost) { + return false; + } + + // 开始施放 + this.state.isCasting = true; + this.state.currentSkill = skill; + this.attributes.mana -= skill.cost; + + // 设置冷却 + this.cooldowns[skillId] = this.scene.time.now + skill.cooldown; + + // 播放技能动画 + if (skill.animation) { + this.animationSystem.playAnimation(skill.animation); + } + + // 执行技能效果 + setTimeout(() => { + this.executeSkillEffect(skill); + this.state.isCasting = false; + this.state.currentSkill = null; + }, skill.castTime || 1000); + + return true; + } + + /** + * 执行技能效果 + * @param {Object} skill + */ + executeSkillEffect(skill) { + // 这里可以实现具体的技能效果 + console.log(`Executing skill: ${skill.name}`); + + // 示例:创建技能特效 + if (skill.effect) { + // 实现技能特效逻辑 + } + } + + /** + * 更新移动逻辑 + */ + updateMovement() { + if (!this.target) return; + + const dx = this.target.x - this.x; + const dy = this.target.y - this.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < 5) { + this.setPosition(this.target.x, this.target.y); + this.clearTarget(); + this.state.isMoving = false; + + // 停止动画,显示静止帧 + this.animationSystem.stopAnimation(); + this.setTexture(this.config.idleTexture || 'player0-0'); + } else { + this.state.isMoving = true; + const speed = this.attributes.speed; + const angle = Math.atan2(dy, dx); + this.setVelocity(Math.cos(angle) * speed, Math.sin(angle) * speed); + + // 处理朝向 + if (Math.cos(angle) < -0.1) { + this.setFlipX(true); + } else if (Math.cos(angle) > 0.1) { + this.setFlipX(false); + } + + // 播放移动动画 + this.animationSystem.playAnimation(this.config.moveAnimation || 'player0-move'); + } + } + + /** + * 绘制路径 + */ + drawPath() { + if (!this.pathGraphics || !this.target) return; + + this.pathGraphics.clear(); + this.pathGraphics.lineStyle(2, 0x00ff00, 0.8); + this.pathGraphics.beginPath(); + this.pathGraphics.moveTo(this.x, this.y); + this.pathGraphics.lineTo(this.target.x, this.target.y); + this.pathGraphics.stroke(); + } + + /** + * 更新 + */ + update() { + // 更新指示器 + this.updateIndicators(); + + // 更新移动 + this.updateMovement(); + + // 更新路径 + if (this.state.isSelected && this.target) { + this.drawPath(); + } + } + + /** + * 更新指示器 + */ + updateIndicators() { + // 更新选中指示器 + if (this.selectedIndicator && this.state.isSelected) { + this.selectedIndicator.setPosition(this.x, this.y); + } + + // 更新目标指示器 + if (this.targetIndicator) { + this.targetIndicator.setVisible(this.state.isSelected && this.target); + } + } + + /** + * 获取属性 + * @param {string} key + */ + getAttribute(key) { + return this.attributes[key]; + } + + /** + * 设置属性 + * @param {string} key + * @param {number} value + */ + setAttribute(key, value) { + this.attributes[key] = value; + } + + /** + * 增加属性 + * @param {string} key + * @param {number} value + */ + addAttribute(key, value) { + if (this.attributes[key] !== undefined) { + this.attributes[key] += value; + } + } +} diff --git a/scenes/BootScene.js b/scenes/BootScene.js index 4e7cb0c..f4f0bfc 100644 --- a/scenes/BootScene.js +++ b/scenes/BootScene.js @@ -17,6 +17,8 @@ export default class BootScene extends Phaser.Scene { // 测试场景列表 const testScenes = [ + { key: 'WeaponTestScene', name: '测试场景22:武器测试' }, + { key: 'CharacterClassTestScene', name: '测试场景21:角色类测试' }, { key: 'MultiTouchTestScene', name: '测试场景20:多触摸测试' }, { key: 'TestObjectsScene', name: '测试场景19:测试对象场景' }, { key: 'TmpScene', name: '测试场景18:临时场景' }, diff --git a/scenes/testScenes/CharacterClassTestScene.js b/scenes/testScenes/CharacterClassTestScene.js new file mode 100644 index 0000000..751ff42 --- /dev/null +++ b/scenes/testScenes/CharacterClassTestScene.js @@ -0,0 +1,513 @@ +// scenes/testScenes/CharacterClassTestScene.js +// 角色类测试场景 + +import { InputSystem } from '../../systems/InputSystem.js'; +import Character from '../../objects/Character.js'; +import { VirtualJoystick } from '../../ui/VirtualJoystick.js'; + +export default class CharacterClassTestScene extends Phaser.Scene { + constructor() { + super({ key: 'CharacterClassTestScene' }); + this.character = null; + this.inputSystem = null; + this.cursors = null; + this.keys = null; + + // 虚拟摇杆相关 + this.virtualJoystick = null; + this.joysticks = []; + + + } + + preload() { + // 加载玩家瓦片图片 + console.log('加载角色资源...'); + + // 加载Player0的动画帧 + for (let i = 0; i < 8; i++) { + this.load.image(`player0-${i}`, `assets/PNG/Players/Tiles/tile_${String(i).padStart(4, '0')}.png`); + } + + // 加载Player1的动画帧 + for (let i = 8; i < 16; i++) { + this.load.image(`player1-${i-8}`, `assets/PNG/Players/Tiles/tile_${String(i).padStart(4, '0')}.png`); + } + + console.log('角色资源加载完成'); + } + + create() { + // 设置物理世界 + const worldSize = 2000; + 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.cameras.main.setBackgroundColor('#222222'); + + // 创建地面网格 + this.createGrid(); + + // 创建角色动画 + this.createAnimations(); + + // 初始化输入系统 + this.inputSystem = new InputSystem(this, { + keyboard: true, + mouse: true, + selection: true + }); + + // 创建单位组 + this.unitGroup = this.add.group(); + + // 初始化技能轮盘 + this.skillWheel = { + centerX: 0, + centerY: 0, + radius: 60, + isActive: false, + activeSkill: null, + activePointer: null, + skillButtons: [], + skillInfo: { + 1: { key: 'skill1', name: '火球术', color: 0xff0000 }, + 2: { key: 'skill2', name: '治疗术', color: 0x00ff00 } + } + }; + + // 创建角色 + this.createCharacter(); + + // 创建虚拟摇杆 + this.createVirtualJoystick(); + + // 创建技能轮盘 + this.createSkillWheel(); + // 绑定技能轮盘事件 + this.bindSkillWheelEvents(); + + // 设置输入控制 + this.setupInput(); + + // 监听move-to-point事件,实现鼠标点击移动 + this.events.on('move-to-point', (x, y) => { + if (this.character) { + this.character.setTarget(x, y); + } + }); + + // 监听select-unit事件 + this.events.on('select-unit', (unit) => { + console.log('单位已选中:', unit); + }); + + // 显示提示信息 + this.showInstructions(); + } + + /** + * 创建地面网格 + */ + createGrid() { + const gridGraphics = this.add.graphics(); + gridGraphics.lineStyle(1, 0x444444, 0.5); + + // 绘制垂直线 + for (let x = 0; x <= 2000; x += 16) { + gridGraphics.moveTo(x, 0); + gridGraphics.lineTo(x, 2000); + } + + // 绘制水平线 + for (let y = 0; y <= 2000; y += 16) { + gridGraphics.moveTo(0, y); + gridGraphics.lineTo(2000, y); + } + } + + /** + * 创建角色动画 + */ + createAnimations() { + console.log('创建角色动画...'); + + // 创建Player0的移动动画 + this.anims.create({ + key: 'player0-move', + frames: [ + { key: 'player0-1' }, + { key: 'player0-2' } + ], + frameRate: 10, + repeat: -1 + }); + + // 创建Player0的技能动画 + this.anims.create({ + key: 'player0-skill', + frames: [ + { key: 'player0-3' }, + { key: 'player0-4' }, + { key: 'player0-5' } + ], + frameRate: 15, + repeat: 0 + }); + + console.log('角色动画创建完成'); + } + + /** + * 创建角色 + */ + createCharacter() { + console.log('创建角色...'); + + // 角色配置 + const characterConfig = { + texture: 'player0-0', + idleTexture: 'player0-0', + moveAnimation: 'player0-move', + health: 100, + mana: 50, + speed: 150, + attack: 20, + defense: 10, + collisionRadius: 14, + skills: [ + { + id: 'skill1', + name: '火球术', + cost: 10, + cooldown: 3000, + castTime: 1000, + animation: 'player0-skill' + }, + { + id: 'skill2', + name: '治疗术', + cost: 15, + cooldown: 5000, + castTime: 1500, + animation: 'player0-skill' + } + ] + }; + + // 创建角色 + this.character = new Character(this, 100, 100, characterConfig); + this.character.setScale(2); + + // 将角色添加到单位组 + this.unitGroup.add(this.character); + + // 自动选中角色 + this.character.setSelected(true); + + console.log('角色创建完成'); + } + + /** + * 设置输入控制 + */ + setupInput() { + // 键盘控制 + this.cursors = this.input.keyboard.createCursorKeys(); + + // 添加WASD键监听 + this.keys = { + a: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A), + d: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D), + w: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W), + s: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S), + space: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE) + }; + + // 技能按键 + this.input.keyboard.on('keydown-Q', () => { + this.character.castSkill('skill1'); + }); + + this.input.keyboard.on('keydown-W', () => { + this.character.castSkill('skill2'); + }); + + // 鼠标点击设置目标由InputSystem处理,通过move-to-point事件 + } + + /** + * 创建虚拟摇杆 + */ + createVirtualJoystick() { + // 创建左侧移动摇杆 + this.virtualJoystick = new VirtualJoystick(this, true); + this.virtualJoystick.centerX = 150; + this.virtualJoystick.centerY = this.scale.height - 150; + this.virtualJoystick.base.setPosition(this.virtualJoystick.centerX, this.virtualJoystick.centerY); + this.virtualJoystick.knob.setPosition(this.virtualJoystick.centerX, this.virtualJoystick.centerY); + this.joysticks.push(this.virtualJoystick); + + // 监听虚拟摇杆移动事件 + this.events.on('move-relative', (direction) => { + if (this.character) { + this.character.moveRelative(direction.x, direction.y); + } + }); + } + + /** + * 创建技能轮盘 + */ + createSkillWheel() { + // 技能轮盘基础位置(右下角) + this.skillWheel.centerX = this.scale.width - 100; + this.skillWheel.centerY = this.scale.height - 100; + + // 创建技能轮盘基础(默认隐藏,选中技能时显示) + this.skillWheel.base = this.add.circle(this.skillWheel.centerX, this.skillWheel.centerY, this.skillWheel.radius, 0x444444, 0.5); + this.skillWheel.base.setScrollFactor(0); // 不随相机移动 + this.skillWheel.base.setDepth(100); + this.skillWheel.base.setVisible(false); + + // 创建技能按钮(扇形排列:技能1-2在右下角左上方,大半径扇形分布) + const skills = [1, 2]; + const startAngle = -Math.PI; // 起始角度(-90度,左) + const endAngle = -Math.PI / 2; // 结束角度(0度,上) + const angleRange = endAngle - startAngle; + const angleStep = angleRange / (skills.length - 1); + + this.skillWheel.skillButtons = []; + for (let i = 0; i < skills.length; i++) { + const skillIndex = skills[i]; + // 计算技能按钮的角度(扇形排列) + const angle = startAngle + i * angleStep; + const distance = 120; // 增大技能按钮距离中心的距离 + const x = this.skillWheel.centerX + Math.cos(angle) * distance; + const y = this.skillWheel.centerY + Math.sin(angle) * distance; + + // 创建技能按钮 + const button = this.add.circle(x, y, 25, this.skillWheel.skillInfo[skillIndex].color, 0.6); + button.setScrollFactor(0); + button.setDepth(100); + + // 添加技能按键文本 + const text = this.add.text(x, y, skillIndex.toString(), { + fontSize: '14px', + fill: '#000000', + fontFamily: 'Arial', + fontWeight: 'bold' + }) + .setOrigin(0.5, 0.5) + .setScrollFactor(0) + .setDepth(101); + + // 保存技能信息 + button.skillIndex = skillIndex; + button.skillKey = this.skillWheel.skillInfo[skillIndex].key; + button.x = x; + button.y = y; + + // 添加点击事件 + button.setInteractive({ useHandCursor: true }); + button.on('pointerdown', (pointer) => { + // 选中技能后,将轮盘中心设置为技能按钮的中心位置 + this.skillWheel.centerX = x; + this.skillWheel.centerY = y; + this.skillWheel.base.setPosition(x, y); + this.skillWheel.base.setVisible(true); + + this.skillWheel.activeSkill = skillIndex; + this.startSkillCast(pointer); + }); + + this.skillWheel.skillButtons.push(button); + } + + // 创建轮盘旋钮 + this.skillWheel.knob = this.add.circle(this.skillWheel.centerX, this.skillWheel.centerY, this.skillWheel.radius * 0.5, 0xff0000, 0.8); + this.skillWheel.knob.setScrollFactor(0); + this.skillWheel.knob.setDepth(101); + this.skillWheel.knob.setVisible(false); + } + + /** + * 绑定技能轮盘事件 + */ + bindSkillWheelEvents() { + // 鼠标移动事件 + this.input.on('pointermove', (ptr) => { + // 只有在技能轮盘激活时才处理 + if (!this.skillWheel.isActive || this.skillWheel.activePointer !== ptr) { + return; + } + + // 更新旋钮位置 + const dx = ptr.x - this.skillWheel.centerX; + const dy = ptr.y - this.skillWheel.centerY; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance > this.skillWheel.radius) { + // 限制在圆内 + const angle = Math.atan2(dy, dx); + const knobX = this.skillWheel.centerX + Math.cos(angle) * this.skillWheel.radius; + const knobY = this.skillWheel.centerY + Math.sin(angle) * this.skillWheel.radius; + this.skillWheel.knob.setPosition(knobX, knobY); + } else { + this.skillWheel.knob.setPosition(ptr.x, ptr.y); + } + }); + + // 鼠标释放事件 + this.input.on('pointerup', (ptr) => { + // 只有在技能轮盘激活时才处理 + if (!this.skillWheel.isActive || this.skillWheel.activePointer !== ptr) { + return; + } + + // 完成技能释放 + this.finishSkillCast(); + }); + } + + /** + * 开始技能施法 + */ + startSkillCast(pointer) { + // 设置技能轮盘状态 + this.skillWheel.isActive = true; + this.skillWheel.activePointer = pointer; + + // 显示旋钮和轮盘基础 + this.skillWheel.knob.setVisible(true); + this.skillWheel.base.setVisible(true); + + // 设置旋钮初始位置为轮盘中心 + this.skillWheel.knob.setPosition(this.skillWheel.centerX, this.skillWheel.centerY); + + // 根据技能索引改变旋钮颜色 + if (this.skillWheel.activeSkill && this.skillWheel.skillInfo[this.skillWheel.activeSkill]) { + this.skillWheel.knob.fillColor = this.skillWheel.skillInfo[this.skillWheel.activeSkill].color; + } + } + + /** + * 完成技能释放 + */ + finishSkillCast() { + // 检查是否有激活的技能和角色 + if (!this.skillWheel.activeSkill || !this.character) { + return; + } + + // 计算技能释放方向 + const dx = this.skillWheel.knob.x - this.skillWheel.centerX; + const dy = this.skillWheel.knob.y - this.skillWheel.centerY; + const distance = Math.sqrt(dx * dx + dy * dy); + + // 只有当旋钮移动到一定距离时才释放技能 + if (distance > 10) { + // 归一化方向向量 + const directionX = dx / distance; + const directionY = dy / distance; + + // 释放技能 + this.character.castSkill(this.skillWheel.skillInfo[this.skillWheel.activeSkill].key); + } + + // 重置技能轮盘状态 + this.skillWheel.isActive = false; + this.skillWheel.activeSkill = null; + this.skillWheel.activePointer = null; + + // 隐藏旋钮和轮盘基础 + this.skillWheel.knob.setVisible(false); + this.skillWheel.base.setVisible(false); + } + + /** + * 显示提示信息 + */ + showInstructions() { + // 标题 + this.add.text(20, 20, '角色类测试场景', { + fontSize: '20px', + fill: '#ffffff', + fontFamily: 'Arial', + fontWeight: 'bold' + }).setScrollFactor(0, 0).setDepth(11); + + // 操作提示 + const instructions = [ + '使用左侧虚拟摇杆移动角色', + '鼠标点击设置移动目标', + '右侧红色按钮:施放火球术', + '右侧绿色按钮:施放治疗术', + '角色会自动播放移动动画', + '按空格键返回启动场景' + ]; + + for (let i = 0; i < instructions.length; i++) { + this.add.text(20, 50 + i * 25, instructions[i], { + fontSize: '14px', + fill: '#ffffff', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + } + + // 显示角色属性 + this.add.text(20, 200, '角色属性:', { + fontSize: '16px', + fill: '#00ff00', + fontFamily: 'Arial', + fontWeight: 'bold' + }).setScrollFactor(0, 0).setDepth(11); + } + + update() { + // 更新输入系统 + if (this.inputSystem) { + this.inputSystem.update(); + } + + // 更新虚拟摇杆 + if (this.virtualJoystick) { + this.virtualJoystick.update(); + } + + // 键盘移动控制 + if (this.cursors && this.keys) { + let moveX = 0; + let moveY = 0; + + if (this.cursors.left.isDown || this.keys.a.isDown) { + moveX = -1; + } else if (this.cursors.right.isDown || this.keys.d.isDown) { + moveX = 1; + } + + if (this.cursors.up.isDown || this.keys.w.isDown) { + moveY = -1; + } else if (this.cursors.down.isDown || this.keys.s.isDown) { + moveY = 1; + } + + // 只有在虚拟摇杆未激活时才使用键盘控制 + if (this.character && (!this.virtualJoystick || !this.virtualJoystick.isActive)) { + this.character.moveRelative(moveX, moveY); + } + } + + // 更新角色 + if (this.character) { + this.character.update(); + } + + // 按空格键返回启动场景 + if (this.keys && this.keys.space.isDown) { + this.scene.start('BootScene'); + } + } +} diff --git a/scenes/testScenes/WeaponTestScene.js b/scenes/testScenes/WeaponTestScene.js new file mode 100644 index 0000000..99e7192 --- /dev/null +++ b/scenes/testScenes/WeaponTestScene.js @@ -0,0 +1,456 @@ +// 武器测试场景 +// 以角色动画场景为基础,使用\assets\PNG\Weapons\Tiles目录下的武器图片 + +// 导入系统和UI组件 +import { InputSystem } from '../../systems/InputSystem.js'; +import { SelectionSystem } from '../../systems/SelectionSystem.js'; +import { CommandSystem } from '../../systems/CommandSystem.js'; + +// 导入Unit类 +import Unit from '../../objects/Unit.js'; + +export default class WeaponTestScene extends Phaser.Scene { + constructor() { + super({ key: 'WeaponTestScene' }); + this.tileSize = 16; // 瓦片大小 + this.player = null; // 玩家角色 + this.inputSystem = null; // 输入系统 + this.selectionSystem = null; // 选择系统 + this.commandSystem = null; // 命令系统 + this.weapons = []; // 武器列表 + this.currentWeaponIndex = 0; // 当前选中的武器索引 + this.weaponDisplay = null; // 武器展示 + } + + preload() { + // 加载玩家瓦片图片 + console.log('加载玩家瓦片图片...'); + + // 加载Player0的动画帧 + for (let i = 0; i < 8; i++) { + this.load.image(`player0-${i}`, `assets/PNG/Players/Tiles/tile_${String(i).padStart(4, '0')}.png`); + } + + // 加载武器图片 + console.log('加载武器图片...'); + for (let i = 0; i < 40; i++) { + this.load.image(`weapon-${i}`, `assets/PNG/Weapons/Tiles/tile_${String(i).padStart(4, '0')}.png`); + } + + console.log('图片加载完成'); + } + + create() { + // 物理世界和相机边界 + const worldSize = 2000; + 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.cameras.main.setBackgroundColor('#222222'); + + // 创建地面网格 + this.createGrid(); + + // 创建角色动画 + this.createCharacterAnimations(); + + // 初始化系统 + this.inputSystem = new InputSystem(this, { + keyboard: true, + mouse: true, + selection: true + }); + this.selectionSystem = new SelectionSystem(this); + this.commandSystem = new CommandSystem(this); + + // 创建单位组 + this.unitGroup = this.add.group(); + + // 初始化武器列表 + this.initWeapons(); + + // 创建玩家角色 + this.createPlayer(); + + // 设置输入控制 + this.setupInput(); + + // 添加事件监听器 + this.addEventListeners(); + + // 添加碰撞检测 + this.physics.add.collider(this.unitGroup, this.unitGroup); + + // 显示提示信息 + this.showInstructions(); + } + + /** + * 添加事件监听器 + */ + addEventListeners() { + // 监听相对移动事件(键盘控制) + this.events.on('move-relative', (dir) => { + if (this.player) { + this.player.moveRelative(dir.x, dir.y); + } + }); + + // 监听移动到指定点事件(鼠标点击) + this.events.on('move-to-point', (x, y) => { + if (this.player) { + this.player.setTarget(x, y); + } + }); + } + + /** + * 创建地面网格 + */ + createGrid() { + // 创建网格线 + const gridGraphics = this.add.graphics(); + gridGraphics.lineStyle(1, 0x444444, 0.5); + + // 绘制垂直线 + for (let x = 0; x <= 2000; x += this.tileSize) { + gridGraphics.moveTo(x, 0); + gridGraphics.lineTo(x, 2000); + } + + // 绘制水平线 + for (let y = 0; y <= 2000; y += this.tileSize) { + gridGraphics.moveTo(0, y); + gridGraphics.lineTo(2000, y); + } + } + + /** + * 创建角色动画 + */ + createCharacterAnimations() { + console.log('创建角色动画...'); + + // 创建Player0的移动动画 + this.anims.create({ + key: 'player0-move', + frames: [ + { key: 'player0-1' }, + { key: 'player0-2' } + ], + frameRate: 10, + repeat: -1 + }); + + console.log('角色动画创建完成'); + } + + /** + * 创建玩家角色 + */ + createPlayer() { + console.log('创建玩家角色...'); + + // 创建玩家角色使用Unit类 + this.player = new Unit(this, 0, 0, 'player0-0'); + this.player.setScale(2); // 放大角色 + this.player.setBounce(0.2); // 反弹效果 + + // 自动选中玩家 + this.events.emit('select-unit', this.player); + + // 将玩家添加到单位组 + this.unitGroup.add(this.player); + + // 创建武器展示 + this.createWeaponDisplay(); + + console.log('玩家角色创建完成'); + } + + /** + * 初始化武器列表 + */ + initWeapons() { + console.log('初始化武器列表...'); + + // 初始化武器数据 + for (let i = 0; i < 40; i++) { + this.weapons.push({ + id: i, + name: `武器 ${i}`, + texture: `weapon-${i}`, + damage: 10 + i, + range: 1 + Math.floor(i / 10) + }); + } + + console.log('武器列表初始化完成,共', this.weapons.length, '件武器'); + } + + /** + * 创建武器展示 + */ + createWeaponDisplay() { + // 武器展示背景 + const displayBg = this.add.rectangle(100, 300, 180, 100, 0x333333); + displayBg.setOrigin(0.5, 0.5); + displayBg.setScrollFactor(0, 0); + displayBg.setDepth(10); + + // 武器图片 + this.weaponDisplay = this.add.image(100, 280, `weapon-${this.currentWeaponIndex}`); + this.weaponDisplay.setOrigin(0.5, 0.5); + this.weaponDisplay.setScale(2); + this.weaponDisplay.setScrollFactor(0, 0); + this.weaponDisplay.setDepth(11); + + // 武器名称 + this.weaponNameText = this.add.text(10, 330, `当前武器: ${this.weapons[this.currentWeaponIndex].name}`, { + fontSize: '14px', + fill: '#ffffff', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + + // 武器属性 + this.weaponStatsText = this.add.text(10, 350, `伤害: ${this.weapons[this.currentWeaponIndex].damage}\n范围: ${this.weapons[this.currentWeaponIndex].range}`, { + fontSize: '12px', + fill: '#cccccc', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + } + + /** + * 更新武器展示 + */ + updateWeaponDisplay() { + const weapon = this.weapons[this.currentWeaponIndex]; + this.weaponDisplay.setTexture(weapon.texture); + this.weaponNameText.setText(`当前武器: ${weapon.name}`); + this.weaponStatsText.setText(`伤害: ${weapon.damage}\n范围: ${weapon.range}`); + } + + /** + * 设置输入控制 + */ + setupInput() { + // 切换武器按钮 + this.createButton(this.sys.game.config.width - 200, 100, '上一件武器', () => { + this.previousWeapon(); + }); + + this.createButton(this.sys.game.config.width - 200, 150, '下一件武器', () => { + this.nextWeapon(); + }); + + // 装备武器按钮 + this.createButton(this.sys.game.config.width - 200, 200, '装备武器', () => { + this.equipWeapon(); + }); + + // 攻击按钮 + this.createButton(this.sys.game.config.width - 200, 250, '攻击', () => { + this.attack(); + }); + + // 返回启动场景按钮 + this.createButton(this.sys.game.config.width - 200, 300, '返回启动场景', () => { + this.scene.start('BootScene'); + }); + } + + /** + * 创建按钮 + */ + createButton(x, y, text, callback) { + // 按钮背景 + const button = this.add.rectangle(x, y, 180, 40, 0x333333); + button.setOrigin(0.5, 0.5); + button.setScrollFactor(0, 0); + button.setDepth(10); + button.setInteractive({ useHandCursor: true }); + + // 按钮文本 + const buttonText = this.add.text(x - 70, y - 15, text, { + fontSize: '14px', + fill: '#ffffff', + fontFamily: 'Arial' + }); + buttonText.setScrollFactor(0, 0); + buttonText.setDepth(11); + + // 按钮事件 + button.on('pointerdown', callback); + + button.on('pointerover', () => { + button.setFillStyle(0x555555); + }); + + button.on('pointerout', () => { + button.setFillStyle(0x333333); + }); + } + + /** + * 切换到上一件武器 + */ + previousWeapon() { + this.currentWeaponIndex = (this.currentWeaponIndex - 1 + this.weapons.length) % this.weapons.length; + this.updateWeaponDisplay(); + console.log('切换到上一件武器:', this.weapons[this.currentWeaponIndex].name); + } + + /** + * 切换到下一件武器 + */ + nextWeapon() { + this.currentWeaponIndex = (this.currentWeaponIndex + 1) % this.weapons.length; + this.updateWeaponDisplay(); + console.log('切换到下一件武器:', this.weapons[this.currentWeaponIndex].name); + } + + /** + * 装备武器 + */ + equipWeapon() { + const weapon = this.weapons[this.currentWeaponIndex]; + this.player.equippedWeapon = weapon; + console.log('装备武器:', weapon.name); + + // 显示装备成功提示 + const equipText = this.add.text(this.sys.game.config.width / 2, 100, `已装备: ${weapon.name}`, { + fontSize: '16px', + fill: '#00ff00', + fontFamily: 'Arial', + fontWeight: 'bold' + }); + equipText.setOrigin(0.5, 0.5); + equipText.setScrollFactor(0, 0); + equipText.setDepth(12); + + // 2秒后移除提示 + this.time.delayedCall(2000, () => { + equipText.destroy(); + }); + } + + /** + * 攻击 + */ + attack() { + if (!this.player.equippedWeapon) { + console.log('请先装备武器'); + return; + } + + console.log('使用武器攻击:', this.player.equippedWeapon.name); + + // 播放攻击动画 + this.player.anims.stop(); + this.player.setTexture('player0-1'); + + // 1秒后恢复 + this.time.delayedCall(500, () => { + this.player.setTexture('player0-0'); + }); + + // 显示攻击效果 + const attackEffect = this.add.circle(this.player.x + 30, this.player.y, 20, 0xff6600, 0.5); + this.tweens.add({ + targets: attackEffect, + scale: { from: 1, to: 2 }, + alpha: { from: 0.5, to: 0 }, + duration: 500, + onComplete: () => { + attackEffect.destroy(); + } + }); + } + + /** + * 显示提示信息 + */ + showInstructions() { + // 标题 + this.add.text(20, 20, '武器测试场景', { + fontSize: '20px', + fill: '#ffffff', + fontFamily: 'Arial', + fontWeight: 'bold' + }).setScrollFactor(0, 0).setDepth(11); + + // 操作提示 + const instructions = [ + 'WASD或方向键移动角色', + '角色移动时播放动画', + '使用按钮切换和装备武器', + '点击攻击按钮测试武器效果', + '按空格键返回启动场景' + ]; + + for (let i = 0; i < instructions.length; i++) { + this.add.text(20, 50 + i * 25, instructions[i], { + fontSize: '14px', + fill: '#ffffff', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + } + + // 武器数量 + this.add.text(20, 200, `武器总数: ${this.weapons.length}`, { + fontSize: '14px', + fill: '#00ff00', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + } + + update() { + // 更新输入系统 + this.inputSystem.update(); + + // 更新所有单位 + this.unitGroup.getChildren().forEach(unit => { + if (unit.update) { + unit.update(); + } + unit.updateMovement(); + + // 处理角色动画 + this.updateCharacterAnimation(unit); + }); + + // 按空格键返回启动场景 + if (this.input.keyboard.checkDown(this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE), 100)) { + this.scene.start('BootScene'); + } + } + + /** + * 更新角色动画 + * @param {Object} unit - 单位对象 + */ + updateCharacterAnimation(unit) { + // 检查单位是否在移动 + const isMoving = Math.abs(unit.body.velocity.x) > 10 || Math.abs(unit.body.velocity.y) > 10; + + if (isMoving) { + // 处理角色朝向 + if (unit.body.velocity.x < -10) { + unit.setFlipX(true); // 向左翻转 + } else if (unit.body.velocity.x > 10) { + unit.setFlipX(false); // 向右不翻转 + } + + // 播放移动动画 + if (!unit.anims.isPlaying || !unit.anims.currentAnim.key.includes('move')) { + unit.play('player0-move'); + } + } else { + // 静止状态,显示图片0 + unit.anims.stop(); + unit.setTexture('player0-0'); + } + } +} \ No newline at end of file