diff --git a/public/libs/core.js b/public/libs/core.js index a577892..fddd4de 100644 --- a/public/libs/core.js +++ b/public/libs/core.js @@ -19,7 +19,11 @@ function core() { this.__HALF_SIZE__ = Math.floor(this.__SIZE__ / 2); this.material = { animates: {}, - images: {}, + images: { + images: {}, + autotile: {}, + tilesets: {} + }, bgms: {}, sounds: {}, items: {}, diff --git a/public/libs/loader.js b/public/libs/loader.js index dbd8795..651f68f 100644 --- a/public/libs/loader.js +++ b/public/libs/loader.js @@ -115,6 +115,7 @@ loader.prototype._load_async = function (callback) { // ----- 加载资源文件 ------ // loader.prototype._loadMaterials_sync = function (callback) { + callback(); this._setStartLoadTipText('正在加载资源文件...'); this.loadImages( 'materials', @@ -122,7 +123,6 @@ loader.prototype._loadMaterials_sync = function (callback) { core.material.images, function () { core.loader._loadMaterials_afterLoad(); - callback(); } ); }; @@ -154,14 +154,7 @@ loader.prototype._loadMaterials_afterLoad = function () { // ------ 加载使用的图片 ------ // loader.prototype._loadExtraImages_sync = function (callback) { - core.material.images.images = {}; - this._setStartLoadTipText('正在加载图片文件...'); - core.loadImages( - 'images', - core.images, - core.material.images.images, - callback - ); + callback(); }; loader.prototype._loadExtraImages_async = function (onprogress, onfinished) { @@ -196,15 +189,7 @@ loader.prototype._loadExtraImages_async = function (onprogress, onfinished) { // ------ 加载自动元件 ------ // loader.prototype._loadAutotiles_sync = function (callback) { - core.material.images.autotile = {}; - var keys = Object.keys(core.material.icons.autotile); - var autotiles = {}; - - this._setStartLoadTipText('正在加载自动元件...'); - this.loadImages('autotiles', keys, autotiles, function () { - core.loader._loadAutotiles_afterLoad(keys, autotiles); - callback(); - }); + callback(); }; loader.prototype._loadAutotiles_async = function (onprogress, onfinished) { @@ -224,30 +209,12 @@ loader.prototype._loadAutotiles_async = function (onprogress, onfinished) { ); }; -loader.prototype._loadAutotiles_afterLoad = function (keys, autotiles) { - // autotile需要保证顺序 - keys.forEach(function (v) { - core.material.images.autotile[v] = autotiles[v]; - }); - - setTimeout(function () { - core.maps._makeAutotileEdges(); - }); -}; +loader.prototype._loadAutotiles_afterLoad = function (keys, autotiles) {}; // ------ 加载额外素材 ------ // loader.prototype._loadTilesets_sync = function (callback) { - core.material.images.tilesets = {}; - this._setStartLoadTipText('正在加载额外素材...'); - this.loadImages( - 'tilesets', - core.tilesets, - core.material.images.tilesets, - function () { - callback(); - } - ); + callback(); }; loader.prototype._loadTilesets_async = function (onprogress, onfinished) { @@ -266,26 +233,7 @@ loader.prototype._loadTilesets_async = function (onprogress, onfinished) { // ------ 实际加载一系列图片 ------ // loader.prototype.loadImages = function (dir, names, toSave, callback) { - if (!names || names.length == 0) { - if (callback) callback(); - return; - } - var items = 0; - for (var i = 0; i < names.length; i++) { - this.loadImage(dir, names[i], function (id, image) { - core.loader._setStartLoadTipText('正在加载图片 ' + id + '...'); - if (toSave[id] !== undefined) { - if (image != null) toSave[id] = image; - return; - } - toSave[id] = image; - items++; - core.loader._setStartProgressVal(items * (100 / names.length)); - if (items == names.length) { - if (callback) callback(); - } - }); - } + return callback(); }; loader.prototype.loadImage = function (dir, imgName, callback) { diff --git a/public/main.js b/public/main.js index decbd2f..e0dbb6e 100644 --- a/public/main.js +++ b/public/main.js @@ -336,10 +336,15 @@ main.prototype.loadAsync = async function (mode, callback) { // 加载核心js代码 if (main.useCompress) { await main.loadScript(`libs/libs.min.js?v=${main.version}`); + main.loading.emit('coreLoaded'); } else { await Promise.all( main.loadList.map(v => - main.loadScript(`libs/${v}.js?v=${main.version}`) + main.loadScript(`libs/${v}.js?v=${main.version}`).then(vv => { + if (v === 'core') { + main.loading.emit('coreLoaded'); + } + }) ) ); } @@ -398,6 +403,8 @@ main.prototype.loadAsync = async function (mode, callback) { coreData[t] = main[t]; }); await core.init(coreData, callback); + main.loading.emit('coreInit'); + core.resize(); main.core = core; diff --git a/src/core/common/eventEmitter.ts b/src/core/common/eventEmitter.ts index f52db37..1b70b00 100644 --- a/src/core/common/eventEmitter.ts +++ b/src/core/common/eventEmitter.ts @@ -5,16 +5,19 @@ export interface EmitableEvent { interface Listener any> { fn: T; once?: boolean; + immediate?: boolean; } interface ListenerOptions { once: boolean; + immediate: boolean; } export class EventEmitter { private events: { [P in keyof T]?: Listener[]; } = {}; + private emitted: (keyof T)[] = []; /** * 监听某个事件 @@ -27,6 +30,16 @@ export class EventEmitter { fn: T[K], options?: Partial ) { + if (options?.immediate && this.emitted.includes(event)) { + fn(); + if (!options.once) { + this.events[event] ??= []; + this.events[event]?.push({ + fn + }); + } + return; + } this.events[event] ??= []; this.events[event]?.push({ fn, @@ -60,6 +73,9 @@ export class EventEmitter { * @param params 传入的参数 */ emit(event: K, ...params: Parameters) { + if (!this.emitted.includes(event)) { + this.emitted.push(event); + } const events = (this.events[event] ??= []); for (let i = 0; i < events.length; i++) { const e = events[i]; diff --git a/src/core/index.ts b/src/core/index.ts index 70ab450..841d710 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -3,8 +3,6 @@ import { SoundController } from './audio/sound'; import { readyAllResource } from './loader/load'; import { ResourceStore, ResourceType } from './loader/resource'; -export {}; - declare global { interface AncTe { sound: SoundController; diff --git a/src/core/loader/load.ts b/src/core/loader/load.ts index 5d4767b..f30d19c 100644 --- a/src/core/loader/load.ts +++ b/src/core/loader/load.ts @@ -1,6 +1,15 @@ import resource from '../../data/resource.json'; +import { has } from '../../plugin/utils'; +import { EmitableEvent, EventEmitter } from '../common/eventEmitter'; import { Resource, getTypeByResource } from './resource'; +interface GameLoadEvent extends EmitableEvent { + coreLoaded: () => void; + autotileLoaded: () => void; + coreInit: () => void; + materialLoaded: () => void; +} + const info = resource; /** @@ -32,3 +41,79 @@ export function readyAllResource() { }); ancTe.resource.forEach(v => v.active()); } + +class GameLoading extends EventEmitter { + private autotileLoaded: number = 0; + private autotileNum?: number; + private autotileListened: boolean = false; + + private materialsNum: number = main.materials.length; + private materialsLoaded: number = 0; + + constructor() { + super(); + this.on( + 'coreInit', + () => { + this.autotileNum = Object.keys( + core.material.icons.autotile + ).length; + }, + { immediate: true } + ); + this.on('materialLoaded', () => { + core.loader._loadMaterials_afterLoad(); + }); + } + + addMaterialLoaded() { + this.once('coreInit', () => { + this.materialsLoaded++; + if (this.materialsLoaded === this.materialsNum) { + this.emit('materialLoaded'); + } + }); + } + + addAutotileLoaded() { + this.once('coreInit', () => { + this.autotileLoaded++; + if (this.autotileLoaded === this.autotileNum) { + this.emit('autotileLoaded'); + } + }); + } + + /** + * 当自动原件加载完毕时 + * @param autotiles 自动原件数组 + */ + onAutotileLoaded( + autotiles: Partial, HTMLImageElement>> + ) { + 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(); + +declare global { + interface Main { + loading: EventEmitter; + } +} +main.loading = loading; diff --git a/src/core/loader/resource.ts b/src/core/loader/resource.ts index ba8a7be..f926857 100644 --- a/src/core/loader/resource.ts +++ b/src/core/loader/resource.ts @@ -4,6 +4,7 @@ import { ensureArray } from '../../plugin/utils'; import { has } from '../../plugin/utils'; import JSZip from 'jszip'; import { EmitableEvent, EventEmitter } from '../common/eventEmitter'; +import { loading } from './load'; interface ResourceData { image: HTMLImageElement; @@ -17,6 +18,8 @@ interface ResourceData { export type ResourceType = keyof ResourceData; export type NonZipResource = Exclude; +const autotiles: Partial, HTMLImageElement>> = {}; + export class Resource< T extends ResourceType = ResourceType > extends Disposable { @@ -59,6 +62,42 @@ export class Resource< document.fonts.add(new FontFace(this.name, v as ArrayBuffer)); } else if (this.type === 'sounds') { ancTe.sound.add(this.uri, v as ArrayBuffer); + } else if (this.type === 'images') { + const name = `${this.name}${this.ext}` as ImageIds; + loading.on( + 'coreLoaded', + () => { + core.material.images.images[name] = v as HTMLImageElement; + }, + { immediate: true } + ); + } else if (this.type === 'materials') { + const name = this.name as SelectKey< + MaterialImages, + HTMLImageElement + >; + + loading.on( + 'coreLoaded', + () => { + core.material.images[name] = v; + }, + { immediate: true } + ); + } else if (this.type === 'autotiles') { + const name = this.name as AllIdsOf<'autotile'>; + autotiles[name] = v; + loading.addAutotileLoaded(); + loading.onAutotileLoaded(autotiles); + } else if (this.type === 'tilesets') { + const name = `${this.name}${this.ext}`; + loading.on( + 'coreLoaded', + () => { + core.material.images.tilesets[name] = v; + }, + { immediate: true } + ); } // 资源加载类型处理 diff --git a/src/types/core.d.ts b/src/types/core.d.ts index 25b734d..bed7599 100644 --- a/src/types/core.d.ts +++ b/src/types/core.d.ts @@ -810,7 +810,7 @@ type CoreStatusBarElements = { readonly [key: string]: HTMLElement; }; -type Materails = [ +type Materials = [ 'animates', 'enemys', 'items', diff --git a/src/types/loader.d.ts b/src/types/loader.d.ts index 831f05d..ac25e9a 100644 --- a/src/types/loader.d.ts +++ b/src/types/loader.d.ts @@ -64,6 +64,8 @@ interface Loader { * @param name 要释放的bgm的id或名称 */ freeBgm(name: BgmIds | NameMapIn): void; + + _loadMaterials_afterLoad(): void; } declare const loader: new () => Loader; diff --git a/src/types/map.d.ts b/src/types/map.d.ts index 7e95a41..09f1cc9 100644 --- a/src/types/map.d.ts +++ b/src/types/map.d.ts @@ -1376,6 +1376,8 @@ interface Maps { * @param doCallback 是否执行该动画的回调函数 */ stopAnimate(id?: number, doCallback?: boolean): void; + + _makeAutotileEdges(): void; } declare const maps: new () => Maps;