mirror of
https://github.com/motajs/template.git
synced 2026-11-03 07:24:30 +08:00
- isolate legacy loading behind internal dependencies - provide memory saves and remove singleton back-edges
274 lines
8.8 KiB
TypeScript
274 lines
8.8 KiB
TypeScript
import { EventEmitter } from 'eventemitter3';
|
|
import { IDamageEnemy, IEnemyCollection } from '@motajs/types';
|
|
|
|
// ----- 加载事件
|
|
interface GameLoadEvent {
|
|
/** 当核心脚本加载完毕时触发 */
|
|
coreLoaded: [];
|
|
/** 当自动元件加载完毕后触发 */
|
|
autotileLoaded: [];
|
|
/** 当核心类初始化完毕后触发 */
|
|
coreInit: [];
|
|
/** 当所有启动必要资源加载完毕后触发 */
|
|
loaded: [];
|
|
/** 当资源构建完毕后触发,后续需要用新的加载系统替代 */
|
|
assetBuilt: [];
|
|
/** 当客户端(渲染端)和数据端都挂载完毕后触发 */
|
|
registered: [];
|
|
/** 当数据端挂载完毕后触发 */
|
|
dataRegistered: [];
|
|
/** 当客户端(渲染端)挂载完毕后触发 */
|
|
clientRegistered: [];
|
|
}
|
|
|
|
class GameLoading extends EventEmitter<GameLoadEvent> {
|
|
private autotileLoaded: number = 0;
|
|
private autotileNum?: number;
|
|
private autotileListened: boolean = false;
|
|
loaded: boolean = false;
|
|
|
|
constructor() {
|
|
super();
|
|
this.once('coreInit', () => {
|
|
this.autotileNum = Object.keys(core.material.icons.autotile).length;
|
|
});
|
|
this.once('loaded', () => {
|
|
this.loaded = true;
|
|
});
|
|
}
|
|
|
|
addAutotileLoaded() {
|
|
this.autotileLoaded++;
|
|
if (this.autotileLoaded === this.autotileNum) {
|
|
this.emit('autotileLoaded');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 当自动元件加载完毕时
|
|
* @param autotiles 自动元件数组
|
|
*/
|
|
onAutotileLoaded(
|
|
autotiles: Partial<Record<AllIdsOf<'autotile'>, ImageBitmap>>
|
|
) {
|
|
if (this.autotileListened) return;
|
|
this.autotileListened = true;
|
|
this.on('autotileLoaded', () => {
|
|
const keys = Object.keys(
|
|
core.material.icons.autotile
|
|
) as AllIdsOf<'autotile'>[];
|
|
|
|
keys.forEach(v => {
|
|
core.material.images.autotile[v] = autotiles[v]!;
|
|
});
|
|
|
|
setTimeout(() => {
|
|
core.maps._makeAutotileEdges();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
export const loading = new GameLoading();
|
|
if (typeof main !== 'undefined') {
|
|
main.loading = loading;
|
|
}
|
|
|
|
let clientRegistered = false;
|
|
let dataRegistered = false;
|
|
|
|
function checkRegistered() {
|
|
if (
|
|
typeof main !== 'undefined' &&
|
|
(main.replayChecking || main.mode === 'editor')
|
|
) {
|
|
clientRegistered = true;
|
|
}
|
|
if (clientRegistered && dataRegistered) {
|
|
loading.emit('registered');
|
|
}
|
|
}
|
|
|
|
loading.once('clientRegistered', () => {
|
|
clientRegistered = true;
|
|
checkRegistered();
|
|
});
|
|
loading.once('dataRegistered', () => {
|
|
dataRegistered = true;
|
|
checkRegistered();
|
|
});
|
|
|
|
export interface GameEvent {
|
|
/** 当游戏初始化时触发,Emitted in libs/events.js resetGame. */
|
|
reset: [];
|
|
/** 当游戏挂载完毕后触发,Emitted in src/App.vue setup. */
|
|
mounted: [];
|
|
/** 当状态栏更新时触发,Emitted in plugin/game/ui.ts updateStatusBar_update */
|
|
statusBarUpdate: [];
|
|
/** 当客户端(渲染端)加载完毕后触发,Emitted in core/index.ts */
|
|
renderLoaded: [];
|
|
/** 当捡拾道具后触发,Emitted in libs/events.js getItem */
|
|
afterGetItem: [
|
|
itemId: AllIdsOf<'items'>,
|
|
x: number,
|
|
y: number,
|
|
isGentleClick: boolean
|
|
];
|
|
/** 当开门后触发,Emitted in libs/events.js _openDoor_animate */
|
|
afterOpenDoor: [doorId: AllIdsOf<'animates'>, x: number, y: number];
|
|
/** 当楼层切换后触发,Emitted in project/functions.js afterChangeFloor */
|
|
afterChangeFloor: [floorId: FloorIds];
|
|
/** 勇士每移动一步时触发,Emitted in project/functions.js moveOneStep */
|
|
moveOneStep: [x: number, y: number, floorId: FloorIds];
|
|
/** 战斗后触发,Emitted in src/game/enemy/battle.ts afterBattle */
|
|
afterBattle: [enemy: IDamageEnemy, x?: number, y?: number];
|
|
/** 楼层切换中触发,具体时刻是楼层切换的正中间,刚刚执行完切换,Emitted in libs/events.js changingFloor */
|
|
changingFloor: [floorId: FloorIds, heroLoc: Loc];
|
|
/** 当某一个图块被设置时触发,Emitted in libs/maps.js setBlock */
|
|
setBlock: [
|
|
x: number,
|
|
y: number,
|
|
floorId: FloorIds,
|
|
newBlock: AllNumbers,
|
|
oldBlock: AllNumbers
|
|
];
|
|
/** 当怪物信息被解析时触发,Emitted in game/enemy/damage.ts */
|
|
enemyExtract: [col: IEnemyCollection];
|
|
/** 当从游戏中回到游戏标题界面时触发,Emitted in lib/events.js restart */
|
|
restart: [];
|
|
/** 当设置背景或前景图块时触发,Emitted in lib/maps.js setBgFgBlock */
|
|
setBgFgBlock: [
|
|
name: 'bg' | 'fg' | 'bg2' | 'fg2',
|
|
number: AllNumbers,
|
|
x: number,
|
|
y: number,
|
|
floorId: FloorIds
|
|
];
|
|
/** 当录像播放在暂停和播放状态间切换时触发,Emitted in lib/control.js */
|
|
replayStatus: [replaying: boolean];
|
|
/** 当加载存档时触发,Emitted in project/functions.js */
|
|
loadData: [];
|
|
/** 当重设 `core.status.hero` 时触发 */
|
|
resetHero: [hero: any];
|
|
}
|
|
|
|
export const hook = new EventEmitter<GameEvent>();
|
|
|
|
interface ListenerEvent {
|
|
// block
|
|
hoverBlock: [block: Block, ev: MouseEvent];
|
|
leaveBlock: [block: Block, ev: MouseEvent, leaveGame: boolean];
|
|
clickBlock: [block: Block, ev: MouseEvent];
|
|
// mouse
|
|
mouseMove: [ev: MouseEvent];
|
|
}
|
|
|
|
class GameListener extends EventEmitter<ListenerEvent> {
|
|
static num: number = 0;
|
|
|
|
num: number = GameListener.num++;
|
|
|
|
mouseX: number = -1;
|
|
mouseY: number = -1;
|
|
|
|
constructor() {
|
|
super();
|
|
if (typeof main === 'undefined' || main.replayChecking) return;
|
|
if (typeof window !== 'undefined' && window.core) {
|
|
this.init();
|
|
} else {
|
|
loading.once('coreInit', () => {
|
|
this.init();
|
|
});
|
|
}
|
|
}
|
|
|
|
private init() {
|
|
// ----- block
|
|
// const data = core.canvas.data.canvas;
|
|
// const getBlockLoc = (px: number, py: number, size: number) => {
|
|
// return [
|
|
// Math.floor(((px * 32) / size + core.bigmap.offsetX) / 32),
|
|
// Math.floor(((py * 32) / size + core.bigmap.offsetY) / 32)
|
|
// ];
|
|
// };
|
|
// // hover & leave & mouseMove
|
|
// data.addEventListener('mousemove', e => {
|
|
// if (
|
|
// core.status.lockControl ||
|
|
// !core.isPlaying() ||
|
|
// !core.status.floorId
|
|
// )
|
|
// return;
|
|
// this.emit('mouseMove', e);
|
|
// const {
|
|
// x: px,
|
|
// y: py,
|
|
// size
|
|
// } = core.actions._getClickLoc(e.offsetX, e.offsetY);
|
|
// const [bx, by] = getBlockLoc(px, py, size);
|
|
// const blocks = core.getMapBlocksObj();
|
|
// if (this.mouseX !== bx || this.mouseY !== by) {
|
|
// const lastBlock = blocks[`${this.mouseX},${this.mouseY}`];
|
|
// const block = blocks[`${bx},${by}`];
|
|
// if (lastBlock) {
|
|
// this.emit('leaveBlock', lastBlock, e, false);
|
|
// }
|
|
// if (block) {
|
|
// this.emit('hoverBlock', block, e);
|
|
// this.mouseX = bx;
|
|
// this.mouseY = by;
|
|
// } else {
|
|
// this.mouseX = -1;
|
|
// this.mouseY = -1;
|
|
// }
|
|
// }
|
|
// });
|
|
// data.addEventListener('mouseleave', e => {
|
|
// if (
|
|
// core.status.lockControl ||
|
|
// !core.isPlaying() ||
|
|
// !core.status.floorId
|
|
// )
|
|
// return;
|
|
// const blocks = core.getMapBlocksObj();
|
|
// const lastBlock = blocks[`${this.mouseX},${this.mouseY}`];
|
|
// if (lastBlock) {
|
|
// this.emit('leaveBlock', lastBlock, e, true);
|
|
// }
|
|
// this.mouseX = -1;
|
|
// this.mouseY = -1;
|
|
// });
|
|
// // click
|
|
// data.addEventListener('click', e => {
|
|
// if (
|
|
// core.status.lockControl ||
|
|
// !core.isPlaying() ||
|
|
// !core.status.floorId
|
|
// )
|
|
// return;
|
|
// const {
|
|
// x: px,
|
|
// y: py,
|
|
// size
|
|
// } = core.actions._getClickLoc(e.offsetX, e.offsetY);
|
|
// const [bx, by] = getBlockLoc(px, py, size);
|
|
// const blocks = core.getMapBlocksObj();
|
|
// const block = blocks[`${bx},${by}`];
|
|
// if (block) {
|
|
// this.emit('clickBlock', block, e);
|
|
// }
|
|
// });
|
|
// ----- mouse
|
|
}
|
|
}
|
|
|
|
/** @deprecated */
|
|
export const gameListener = new GameListener();
|
|
|
|
declare global {
|
|
interface Main {
|
|
loading: GameLoading;
|
|
}
|
|
}
|