图片加载

This commit is contained in:
unanmed 2023-06-28 22:48:15 +08:00
parent 2e0770ae71
commit e947a1e6e8
10 changed files with 164 additions and 63 deletions

View File

@ -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: {},

View File

@ -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) {

View File

@ -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;

View File

@ -5,16 +5,19 @@ export interface EmitableEvent {
interface Listener<T extends (...params: any) => any> {
fn: T;
once?: boolean;
immediate?: boolean;
}
interface ListenerOptions {
once: boolean;
immediate: boolean;
}
export class EventEmitter<T extends EmitableEvent = {}> {
private events: {
[P in keyof T]?: Listener<T[P]>[];
} = {};
private emitted: (keyof T)[] = [];
/**
*
@ -27,6 +30,16 @@ export class EventEmitter<T extends EmitableEvent = {}> {
fn: T[K],
options?: Partial<ListenerOptions>
) {
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<T extends EmitableEvent = {}> {
* @param params
*/
emit<K extends keyof T>(event: K, ...params: Parameters<T[K]>) {
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];

View File

@ -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;

View File

@ -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<GameLoadEvent> {
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<Record<AllIdsOf<'autotile'>, 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<GameLoadEvent>;
}
}
main.loading = loading;

View File

@ -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<ResourceType, 'zip'>;
const autotiles: Partial<Record<AllIdsOf<'autotile'>, HTMLImageElement>> = {};
export class Resource<
T extends ResourceType = ResourceType
> extends Disposable<string> {
@ -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 }
);
}
// 资源加载类型处理

2
src/types/core.d.ts vendored
View File

@ -810,7 +810,7 @@ type CoreStatusBarElements = {
readonly [key: string]: HTMLElement;
};
type Materails = [
type Materials = [
'animates',
'enemys',
'items',

View File

@ -64,6 +64,8 @@ interface Loader {
* @param name bgm的id或名称
*/
freeBgm(name: BgmIds | NameMapIn<BgmIds>): void;
_loadMaterials_afterLoad(): void;
}
declare const loader: new () => Loader;

2
src/types/map.d.ts vendored
View File

@ -1376,6 +1376,8 @@ interface Maps {
* @param doCallback
*/
stopAnimate(id?: number, doCallback?: boolean): void;
_makeAutotileEdges(): void;
}
declare const maps: new () => Maps;