feat(control) 多角色控制

This commit is contained in:
chicrobot committed 2025-12-30 21:45:25 +08:00
1 parent be5ee91328
commit f86e5f3a79
11 files changed
+431

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
// systems/CommandSystem.js
import { activeUnit, selectedUnits } from './ControlMode.js';
export class CommandSystem {
constructor(scene) {
this.scene = scene;
scene.events.on('move-relative', this.onMoveRelative, this);
scene.events.on('move-to-point', this.onMoveToPoint, this);
scene.events.on('select-unit', this.onSelectUnit, this);
}
onMoveRelative(dir) {
if (activeUnit) {
activeUnit.moveRelative(dir.x, dir.y);
}
}
onMoveToPoint(x, y) {
const targets = selectedUnits.length > 0 ? selectedUnits : (activeUnit ? [activeUnit] : []);
targets.forEach(unit => unit.moveTo(x, y));
}
onSelectUnit(unit) {
// 切换单位
import('./ControlMode.js').then(mod => {
mod.setActiveUnit(unit);
this.scene.events.emit('unit-activated', unit);
});
}
}
+24
View File
@@ -0,0 +1,24 @@
export const CONTROL_MODE = {
SINGLE: 'single',
GROUP: 'group',
JOYSTICK: 'joystick'
};
export let activeUnit = null;
export let selectedUnits = [];
export function setActiveUnit(unit) {
activeUnit = unit;
selectedUnits = unit ? [unit] : [];
}
export function addToSelection(unit) {
if (!selectedUnits.includes(unit)) {
selectedUnits.push(unit);
}
}
export function clearSelection() {
activeUnit = null;
selectedUnits = [];
}
+86
View File
@@ -0,0 +1,86 @@
// systems/InputSystem.js
import { clearSelection, setActiveUnit } from './ControlMode.js';
export class InputSystem {
constructor(scene) {
this.scene = scene;
this.selectionStart = null;
// 初始化键盘
const kb = scene.input.keyboard;
this.keys = {
up: [kb.addKey(Phaser.Input.Keyboard.KeyCodes.W), kb.addKey(Phaser.Input.Keyboard.KeyCodes.UP)],
down: [kb.addKey(Phaser.Input.Keyboard.KeyCodes.S), kb.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN)],
left: [kb.addKey(Phaser.Input.Keyboard.KeyCodes.A), kb.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT)],
right: [kb.addKey(Phaser.Input.Keyboard.KeyCodes.D), kb.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT)]
};
// 鼠标/触摸事件
scene.input.on('pointerdown', this.onPointerDown, this);
scene.input.on('pointerup', this.onPointerUp, this);
}
isKeyDown(keyGroup) {
return keyGroup.some(key => key.isDown);
}
update() {
// 键盘相对移动(仅当有激活单位)
const dir = { x: 0, y: 0 };
if (this.isKeyDown(this.keys.left)) dir.x -= 1;
if (this.isKeyDown(this.keys.right)) dir.x += 1;
if (this.isKeyDown(this.keys.up)) dir.y -= 1;
if (this.isKeyDown(this.keys.down)) dir.y += 1;
if (dir.x !== 0 || dir.y !== 0) {
this.scene.events.emit('move-relative', dir);
}
}
onPointerDown(pointer) {
if (pointer.leftButtonDown()) {
const worldX = pointer.worldX;
const worldY = pointer.worldY;
// 检查是否点中某个单位
let clickedUnit = null;
this.scene.unitGroup.getChildren().forEach(unit => {
const bounds = unit.getBounds();
if (worldX >= bounds.x && worldX <= bounds.right &&
worldY >= bounds.y && worldY <= bounds.bottom) {
clickedUnit = unit;
}
});
if (clickedUnit) {
// 切换控制目标
this.scene.events.emit('select-unit', clickedUnit);
} else {
// 开始框选或移动指令
this.selectionStart = { x: pointer.x, y: pointer.y };
this.scene.events.emit('selection-start', this.selectionStart);
}
}
}
onPointerUp(pointer) {
if (this.selectionStart) {
const rect = new Phaser.Geom.Rectangle(
Math.min(this.selectionStart.x, pointer.x),
Math.min(this.selectionStart.y, pointer.y),
Math.abs(pointer.x - this.selectionStart.x),
Math.abs(pointer.y - this.selectionStart.y)
);
// 如果框太小,视为“点击地面移动”
if (rect.width < 10 && rect.height < 10) {
this.scene.events.emit('move-to-point', pointer.worldX, pointer.worldY);
} else {
// 否则执行框选
this.scene.events.emit('selection-end', rect);
}
this.selectionStart = null;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
// systems/SelectionSystem.js
import { clearSelection, addToSelection, setActiveUnit } from './ControlMode.js';
export class SelectionSystem {
constructor(scene) {
this.scene = scene;
this.selectionBox = null;
scene.events.on('selection-start', this.onStart, this);
scene.events.on('selection-end', this.onEnd, this);
}
onStart(pos) {
if (!this.selectionBox) {
this.selectionBox = this.scene.add.rectangle(pos.x, pos.y, 1, 1, 0x00ff00, 0.3)
.setStrokeStyle(1, 0xffffff)
.setVisible(true);
} else {
this.selectionBox.setPosition(pos.x, pos.y).setSize(1, 1).setVisible(true);
}
}
onEnd(rect) {
if (this.selectionBox) {
this.selectionBox.setVisible(false);
}
const units = this.scene.unitGroup.getChildren();
const selected = units.filter(unit => {
const unitRect = unit.getBounds();
return Phaser.Geom.Rectangle.Overlaps(rect, unitRect);
});
clearSelection();
selected.forEach(addToSelection);
if (selected.length > 0) {
setActiveUnit(selected[0]); // 激活第一个
this.scene.events.emit('units-selected', selected);
}
}
}