@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
166 lines (124 loc) • 4.46 kB
JavaScript
import { assert } from "../../core/assert.js";
import { array_remove_first } from "../../core/collection/array/array_remove_first.js";
import { logger } from "../../engine/logging/GlobalLogger.js";
import { AssetLoaderStatusView } from "../asset/AssetLoaderStatusView.js";
import TaskProgressView from "./TaskProgressView.js";
/**
* @type {TaskLoadingScreen}
*/
let _instance;
export class TaskLoadingScreen {
_active_promise = Promise.resolve();
/**
*
* @type {number}
* @private
*/
_release_delay_seconds = 0.5;
/**
*
* @type {number}
* @private
*/
_release_delay_handle = -1;
_pending_cleanup = [];
_state_stack = [];
_clearReleaseTimeout() {
if (this._release_delay_handle !== -1) {
clearTimeout(this._release_delay_handle);
this._release_delay_handle = -1;
}
}
/**
*
* @param {Engine} engine
* @param {Task|TaskGroup} task
* @returns {Promise<void>}
*/
async load(engine, task) {
assert.defined(task, 'task');
assert.notNull(task, 'task');
assert.defined(engine, 'engine');
assert.notNull(engine, 'engine');
await Promise.allSettled([this._active_promise]);
this._clearReleaseTimeout();
const localization = engine.localization;
const taskProgressView = new TaskProgressView({ task, localization });
taskProgressView.el.classList.add('loading-screen');
//add asset manager loading progress
const loaderStatusView = new AssetLoaderStatusView({ assetManager: engine.assetManager, localization });
taskProgressView.addChild(loaderStatusView);
taskProgressView.link();
const graphics = engine.graphics;
const engine_state = {
engine_rendering_enabled: engine.renderingEnabled,
graphics_auto_draw: graphics.autoDraw
};
this._state_stack.push(engine_state);
const domParent = document.body;
domParent.appendChild(taskProgressView.el);
// suspend rendering
engine.renderingEnabled = false;
graphics.autoDraw = false;
const attempt_cleanup = () => {
if (this._active_promise !== promise) {
return;
}
// clear any pending timeouts if they exist
this._clearReleaseTimeout();
// run all remaining pending cleanup tasks
for (let i = 0; i < this._pending_cleanup.length; i++) {
const t = this._pending_cleanup[i];
if (t === cleanup) {
// skip self
continue;
}
try {
t();
} catch (e) {
logger.error(e);
}
// just to make sure, try to remove it again
array_remove_first(this._pending_cleanup, t);
// update iterator
i--;
}
// this is the last task in the queue
this._release_delay_handle = setTimeout(() => {
cleanup();
}, Math.ceil(this._release_delay_seconds * 1000));
}
const cleanup = () => {
array_remove_first(this._pending_cleanup, cleanup);
domParent.removeChild(taskProgressView.el);
taskProgressView.unlink();
// restore state
const state = this._state_stack.pop();
engine.renderingEnabled = state.engine_rendering_enabled;
engine.graphics.autoDraw = state.graphics_auto_draw;
};
this._pending_cleanup.push(cleanup);
const promise = task.promise().finally(attempt_cleanup);
this._active_promise = promise;
return promise;
}
/**
*
* @param {Engine} engine
* @param {Task|TaskGroup} task
* @returns {Promise<void>}
*/
static load(engine, task) {
return TaskLoadingScreen.instance.load(engine, task);
}
/**
*
* @returns {TaskLoadingScreen}
*/
static get instance() {
if (_instance === undefined) {
_instance = new TaskLoadingScreen();
}
return _instance;
}
}