// ui/VirtualJoystick.js export class VirtualJoystick { constructor(scene, enabled = true) { this.scene = scene; this.isActive = false; this.base = null; this.knob = null; this.activePointer = null; // 保持单一激活指针,但允许不同指针触发 this.centerX = 0; this.centerY = 0; this.radius = 50; this.enabled = enabled; // 仅在启用时创建摇杆 if (this.enabled) { // 在所有设备上都显示摇杆 this.create(); this.bindEvents(); } } create() { const x = 200; const y = this.scene.scale.height - 200; this.centerX = x; this.centerY = y; this.base = this.scene.add.circle(x, y, this.radius, 0x444444, 0.5); this.knob = this.scene.add.circle(x, y, this.radius * 0.5, 0xff0000, 0.8); this.base.setScrollFactor(0); // 不随相机移动 this.knob.setScrollFactor(0); } bindEvents() { this.scene.input.on('pointerdown', (ptr) => { if (this.isInBase(ptr)) { // 只有在没有激活指针时才设置新指针 // 这样可以避免不同触摸点之间的干扰 if (!this.isActive) { this.activePointer = ptr; this.isActive = true; } } }); this.scene.input.on('pointermove', (ptr) => { if (this.isActive && this.activePointer === ptr) { const dx = ptr.x - this.centerX; const dy = ptr.y - this.centerY; const distance = Math.sqrt(dx * dx + dy * dy); if (distance > this.radius) { // 限制在圆内 const angle = Math.atan2(dy, dx); const knobX = this.centerX + Math.cos(angle) * this.radius; const knobY = this.centerY + Math.sin(angle) * this.radius; this.knob.setPosition(knobX, knobY); } else { this.knob.setPosition(ptr.x, ptr.y); } // 发送相对方向(归一化) const dirX = dx / this.radius; const dirY = dy / this.radius; this.scene.events.emit('move-relative', { x: dirX, y: dirY }); } }); this.scene.input.on('pointerup', (ptr) => { if (this.activePointer === ptr) { this.isActive = false; this.activePointer = null; this.knob.setPosition(this.centerX, this.centerY); this.scene.events.emit('move-relative', { x: 0, y: 0 }); // 停止 } }); // 处理指针离开屏幕的情况 this.scene.input.on('pointerout', (ptr) => { if (this.activePointer === ptr) { this.isActive = false; this.activePointer = null; this.knob.setPosition(this.centerX, this.centerY); this.scene.events.emit('move-relative', { x: 0, y: 0 }); // 停止 } }); } isInBase(pointer) { const dx = pointer.x - this.centerX; const dy = pointer.y - this.centerY; return Math.sqrt(dx * dx + dy * dy) <= this.radius + 20; // 容差 } /** * 更新方法,用于在游戏循环中持续发送移动指令 */ update() { // 仅在启用时更新 if (this.enabled && this.isActive && this.activePointer) { const dx = this.activePointer.x - this.centerX; const dy = this.activePointer.y - this.centerY; // 发送相对方向(归一化) const dirX = dx / this.radius; const dirY = dy / this.radius; this.scene.events.emit('move-relative', { x: dirX, y: dirY }); } } }