mirror of
https://github.com/motajs/template.git
synced 2026-10-03 01:10:18 +08:00
183 lines
4.9 KiB
TypeScript
183 lines
4.9 KiB
TypeScript
import { KeyCode } from '@motajs/client-base';
|
|
import { Hotkey, HotkeyData } from '@motajs/system';
|
|
import { HeroMover, IMoveController } from '@user/data-state';
|
|
import { Ticker } from 'mutate-animate';
|
|
import { mainScope } from './hotkey';
|
|
|
|
type MoveKey = Record<Dir, HotkeyData>;
|
|
type MoveKeyConfig = Record<Dir, string>;
|
|
|
|
export class HeroKeyMover {
|
|
/** 当前按下的键 */
|
|
private pressedKey: Set<Dir> = new Set();
|
|
/** 当前的移动方向 */
|
|
private moveDir: Dir = 'down';
|
|
/** 当前是否正在使用按键移动 */
|
|
private moving: boolean = false;
|
|
/** 当前移动的控制器 */
|
|
private controller?: IMoveController;
|
|
|
|
/** 按键接续ticker */
|
|
private ticker = new Ticker();
|
|
|
|
/** 当前移动实例绑定的热键 */
|
|
hotkey: Hotkey;
|
|
/** 当前热键的移动按键信息 */
|
|
hotkeyData: MoveKey;
|
|
/** 移动实例 */
|
|
mover: HeroMover;
|
|
/** 移动可触发的作用域 */
|
|
scope: symbol = mainScope;
|
|
|
|
constructor(hotkey: Hotkey, mover: HeroMover, config?: MoveKeyConfig) {
|
|
this.hotkey = hotkey;
|
|
this.mover = mover;
|
|
hotkey.on('press', this.onPressKey);
|
|
hotkey.on('release', this.onReleaseKey);
|
|
|
|
const data = hotkey.data;
|
|
|
|
this.hotkeyData = {
|
|
left: data[config?.left ?? 'moveLeft'],
|
|
right: data[config?.right ?? 'moveRight'],
|
|
up: data[config?.up ?? 'moveUp'],
|
|
down: data[config?.down ?? 'moveDown']
|
|
};
|
|
|
|
// 静止时尝试启动移动
|
|
this.ticker.add(() => {
|
|
if (!this.moving) {
|
|
if (this.pressedKey.size > 0) {
|
|
const dir = [...this.pressedKey].at(-1);
|
|
if (!dir) return;
|
|
this.moveDir = dir;
|
|
this.tryStartMove();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 按键移动
|
|
* @param code 按键码
|
|
*/
|
|
private onPressKey = (code: KeyCode) => {
|
|
if (core.isReplaying() || !core.isPlaying()) return;
|
|
core.waitHeroToStop();
|
|
if (code === this.hotkeyData.left.key) this.press('left');
|
|
else if (code === this.hotkeyData.right.key) this.press('right');
|
|
else if (code === this.hotkeyData.up.key) this.press('up');
|
|
else if (code === this.hotkeyData.down.key) this.press('down');
|
|
};
|
|
|
|
/**
|
|
* 释放按键
|
|
* @param code 按键码
|
|
*/
|
|
private onReleaseKey = (code: KeyCode) => {
|
|
if (code === this.hotkeyData.left.key) this.release('left');
|
|
else if (code === this.hotkeyData.right.key) this.release('right');
|
|
else if (code === this.hotkeyData.up.key) this.release('up');
|
|
else if (code === this.hotkeyData.down.key) this.release('down');
|
|
};
|
|
|
|
/**
|
|
* 设置按键触发作用域
|
|
*/
|
|
setScope(scope: symbol) {
|
|
this.scope = scope;
|
|
}
|
|
|
|
/**
|
|
* 按下某个方向键
|
|
* @param dir 移动方向
|
|
*/
|
|
press(dir: Dir) {
|
|
if (this.hotkey.scope !== this.scope || core.status.lockControl) return;
|
|
this.pressedKey.add(dir);
|
|
this.moveDir = dir;
|
|
if (!this.moving) {
|
|
this.tryStartMove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 松开方向键
|
|
* @param dir 移动方向
|
|
*/
|
|
release(dir: Dir) {
|
|
this.pressedKey.delete(dir);
|
|
if (this.pressedKey.size > 0) {
|
|
this.moveDir = [...this.pressedKey][0];
|
|
} else {
|
|
this.endMove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 尝试开始移动
|
|
* @returns 是否成功开始移动
|
|
*/
|
|
tryStartMove() {
|
|
if (this.moving || core.status.lockControl) return false;
|
|
|
|
this.mover.oneStep(this.moveDir);
|
|
const controller = this.mover.startMove(false, false, false, true);
|
|
if (!controller) return false;
|
|
|
|
this.controller = controller;
|
|
controller.onEnd.then(() => {
|
|
this.moving = false;
|
|
this.controller = void 0;
|
|
this.mover.off('stepEnd', this.onStepEnd);
|
|
});
|
|
this.moving = true;
|
|
|
|
this.mover.on('stepEnd', this.onStepEnd);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 停止本次按键移动
|
|
*/
|
|
endMove() {
|
|
this.controller?.stop();
|
|
}
|
|
|
|
/**
|
|
* 移动结束
|
|
*/
|
|
private onStepEnd = () => {
|
|
const con = this.controller;
|
|
if (!con) return;
|
|
|
|
// 被禁止操作时
|
|
if (core.status.lockControl) {
|
|
con.stop();
|
|
return;
|
|
}
|
|
|
|
// 未移动时
|
|
if (!this.moving) {
|
|
con.stop();
|
|
return;
|
|
}
|
|
|
|
// 尝试移动
|
|
if (this.pressedKey.size > 0) {
|
|
if (con.queue.length === 0) {
|
|
con.push({ type: 'dir', value: this.moveDir });
|
|
}
|
|
} else {
|
|
con.stop();
|
|
}
|
|
};
|
|
|
|
destroy() {
|
|
this.hotkey.off('press', this.onPressKey);
|
|
this.hotkey.off('release', this.onReleaseKey);
|
|
this.mover.off('stepEnd', this.onStepEnd);
|
|
this.ticker.destroy();
|
|
}
|
|
}
|