import { CONST, ERROR_CODES, WARNING_CODES } from "../constants.js";
import { ScreenPageData } from "./ScreenPageData.js";
import { Exception, Warning } from "./Exception.js";
import { Logger } from "./Logger.js";
import AssetsManager from "../../modules/assetsm/dist/assetsm.min.js";
import { TiledRenderLayer } from "./TiledRenderLayer.js";
import { RenderInterface } from "./RenderInterface.js";
import { DrawObjectFactory } from "./DrawObjectFactory.js";
import { DrawCircleObject } from "./DrawCircleObject.js";
import { DrawConusObject } from "./DrawConusObject.js";
import { DrawImageObject } from "./DrawImageObject.js";
import { DrawLineObject } from "./DrawLineObject.js";
import { DrawPolygonObject } from "./DrawPolygonObject.js";
import { DrawRectObject } from "./DrawRectObject.js";
import { DrawTextObject } from "./DrawTextObject.js";
import { SystemInterface } from "./SystemInterface.js";
import { SystemAudioInterface } from "./SystemAudioInterface.js";
import { SystemSettings } from "../configs.js";
import { isPointLineIntersect, isPolygonLineIntersect, angle_2points, isCircleLineIntersect } from "../utils.js";
import { Vector } from "./Primitives.js";
import { DrawShapeObject } from "./DrawShapeObject.js";
/**
* Represents the page of the game,<br>
* Register and holds CanvasInterface.<br>
* Contains pages logic.<br>
* Instances should be created and registered with System.registerPage() factory method
*
* @see {@link System} instances of this class holds by the System class
* @hideconstructor
*/
export class ScreenPage {
/**
* @type {string}
*/
#name;
/**
* @type {boolean}
*/
#isInitiated = false;
/**
* @type {boolean}
*/
#isActive;
/**
* @type {SystemInterface}
*/
#systemReference;
/**
* @type {RenderInterface}
*/
#renderInterface;
/**
* @type {Array<number>}
*/
#tempFPStime;
/**
* @type {NodeJS.Timer}
*/
#fpsAverageCountTimer;
/**
* @type {EventTarget}
*/
#emitter = new EventTarget();
/**
* @type {boolean}
*/
#isBoundariesPrecalculations = false;
#minCircleTime;
constructor() {
this.#isActive = false;
//this.#views = new Map();
this.#tempFPStime = [];
}
/**
*
* @param {string} eventName
* @param {...any} eventParams
*/
emit = (eventName, ...eventParams) => {
const event = new Event(eventName);
event.data = [...eventParams];
this.#emitter.dispatchEvent(event);
};
/**
*
* @param {string} eventName
* @param {*} listener
* @param {*=} options
*/
addEventListener = (eventName, listener, options) => {
this.#emitter.addEventListener(eventName, listener, options);
};
/**
*
* @param {string} eventName
* @param {*} listener
* @param {*=} options
*/
removeEventListener = (eventName, listener, options) => {
this.#emitter.removeEventListener(eventName, listener, options);
};
/**
* Register stage
* @param {string} name
* @param {SystemInterface} system
* @ignore
*/
_register(name, system) {
this.#name = name;
this.#systemReference = system;
this.#isBoundariesPrecalculations = this.systemSettings.gameOptions.render.boundaries.wholeWorldPrecalculations;
this.#minCircleTime = this.systemSettings.gameOptions.render.minCircleTime;
this.#renderInterface = new RenderInterface(this.#name, this.#systemReference.systemSettings, this.loader);
this.#setWorldDimensions();
this.#setCanvasSize();
this.register();
}
/**
* Initialization stage
* @ignore
*/
_init() {
this.init();
if (this.systemSettings.gameOptions.boundaries.drawLayerBoundaries) {
this.createCanvasView(CONST.LAYERS.BOUNDARIES);
}
this.#isInitiated = true;
}
/**
* @tutorial screen_pages_stages
* Custom logic for register stage
*/
register() {}
/**
* @tutorial screen_pages_stages
* Custom logic for init stage
*/
init() {}
/**
* Custom logic for start stage
* @param {Object=} options
*/
start(options) {}
/**
* @tutorial screen_pages_stages
* Custom logic for stop stage
*/
stop() {}
/**
* Custom logic for resize stage
*/
resize() {}
/**
* @tutorial assets_manager
* @type {AssetsManager}
*/
get loader() {
return this.#systemReference.loader;
}
/**
* @type {DrawObjectFactory}
*/
get draw() {
return this.#systemReference.drawObjectFactory;
}
/**
* Creates new canvas layer
* and set it to the #views
* @param {string} name
* @param {boolean} [isOffsetTurnedOff = false] - determines if offset is affected on this layer or not
* @returns {CanvasView}
*/
createCanvasView = (name, isOffsetTurnedOff = false) => {
if (name && name.trim().length > 0) {
console.warn("createCanvasView is deprecated");
//const newView = new CanvasView(name, this.#system.systemSettings, this.#screenPageData, this.loader, this.system.webGlInterface, isOffsetTurnedOff);
//this.#views.set(name, newView);
return {};//newView;
} else
Exception(ERROR_CODES.UNEXPECTED_INPUT_PARAMS);
};
/**
* Attach all canvas elements from the #views to container
* @param {HTMLElement} container
* @ignore
*/
_attachViewsToContainer(container) {
this.#attachElementToContainer(this.canvasHtmlElement, container);
//for (const view of this.#views.values()) {
// this.#attachElementToContainer(view.canvas, container);
//}
}
/**
* Add render object to the view
* @param {string} canvasKey
* @param { DrawConusObject | DrawImageObject |
* DrawLineObject | DrawPolygonObject |
* DrawRectObject | DrawCircleObject |
* DrawTextObject } renderObject
*/
addRenderObject = (canvasKey, renderObject) => {
if (!canvasKey) {
Exception(ERROR_CODES.CANVAS_KEY_NOT_SPECIFIED, ", should pass canvasKey as 3rd parameter");
//} else if (!this.#views.has(canvasKey)) {
// Exception(ERROR_CODES.CANVAS_WITH_KEY_NOT_EXIST, ", should create canvas view, with " + canvasKey + " key first");
} else {
//const view = this.#views.get(canvasKey);
const data = this.screenPageData;
data._renderObject = renderObject;
data._sortRenderObjectsBySortIndex();
}
};
/**
* Add render layer to the view
* @param {string} canvasKey
* @param {string} layerKey
* @param {string} tileMapKey
* @param {boolean=} setBoundaries
* @param {DrawShapeObject=} shapeMask
*/
addRenderLayer = (canvasKey, layerKey, tileMapKey, setBoundaries, shapeMask) => {
if (!canvasKey) {
Exception(ERROR_CODES.CANVAS_KEY_NOT_SPECIFIED, ", should pass canvasKey as 3rd parameter");
//} else if (!this.#views.has(canvasKey)) {
// Exception(ERROR_CODES.CANVAS_WITH_KEY_NOT_EXIST, ", should create canvas view, with " + canvasKey + " key first");
} else {
//const view = this.#views.get(canvasKey);
const data = this.screenPageData;
data._renderObject = new TiledRenderLayer(layerKey, tileMapKey, setBoundaries, shapeMask);
if (setBoundaries && this.systemSettings.gameOptions.render.boundaries.mapBoundariesEnabled) {
data._enableMapBoundaries();
}
data._sortRenderObjectsBySortIndex();
}
};
/**
* Determines if this page render is Active or not
* @type {boolean}
*/
get isActive() {
return this.#isActive;
}
/**
* Determines if this page is initialized or not
* @type {boolean}
*/
get isInitiated() {
return this.#isInitiated;
}
/**
* Current page name
* @type {string}
*/
get name () {
return this.#name;
}
/**
* Determines if all added files was loaded or not
* @returns {boolean}
*/
isAllFilesLoaded = () => {
return this.loader.filesWaitingForUpload === 0;
};
/**
* @type {ScreenPageData}
*/
get screenPageData() {
return this.#renderInterface.screenPageData;
}
/**
* @type {SystemSettings}
*/
get systemSettings() {
return this.#systemReference.systemSettings;
}
/**
* @type {SystemAudioInterface}
*/
get audio() {
return this.#systemReference.audio;
}
/**
* @type {SystemInterface}
*/
get system() {
return this.#systemReference;
}
get canvasHtmlElement() {
return this.#renderInterface.canvas;
}
/**
*
*/
get canvasInterface() {
return this.#renderInterface;
}
/**
* @method
* @param {string} key
* @returns {CanvasView | undefined}
*/
getView = (key) => {
console.warn("ScreenPage.getView() is deprecated. Use ScreenPage.canvas instead");
return;
/*
const ctx = this.#views.get(key);
if (ctx) {
return this.#views.get(key);
} else {
Exception(ERROR_CODES.CANVAS_WITH_KEY_NOT_EXIST, ", cannot find canvas with key " + key);
}*/
};
/**
* Start page render
* @param {Object=} options
* @ignore
*/
_start(options) {
this.start(options);
this.#isActive = true;
window.addEventListener("resize", this._resize);
this._resize();
//if (this.#views.size > 0) {
requestAnimationFrame(this.#render);
//}
this.emit(CONST.EVENTS.SYSTEM.START_PAGE);
this._resize();
}
/**
* Stop page render
* @ignore
*/
_stop() {
this.#isActive = false;
window.removeEventListener("resize", this._resize);
this.emit(CONST.EVENTS.SYSTEM.STOP_PAGE);
this.#removeCanvasFromDom();
clearInterval(this.#fpsAverageCountTimer);
this.stop();
}
/**
* Resize event
* @ignore
*/
_resize = () => {
this.#setCanvasSize();
this.resize();
};
/**
*
* @param {HTMLCanvasElement} htmlElement
* @param {HTMLElement} container
*/
#attachElementToContainer(htmlElement, container) {
container.appendChild(htmlElement);
}
#removeCanvasFromDom() {
for (const canvas of document.getElementsByTagName("canvas")) {
canvas.remove();
}
//for (const view of this.#views.values()) {
// document.getElementById(view.canvas.id).remove();
// }
}
#setWorldDimensions() {
const width = this.systemSettings.worldSize ? this.systemSettings.worldSize.width : 0,
height = this.systemSettings.worldSize ? this.systemSettings.worldSize.height : 0;
this.screenPageData._setWorldDimensions(width, height);
}
//////////////////////////////////////////////////////
//***************************************************/
//****************** Collisions ********************//
//**************************************************//
//////////////////////////////////////////////////////
/**
*
* @param {number} x
* @param {number} y
* @param {DrawImageObject} drawObject
* @returns {{x:number, y:number, p:number} | boolean}
*/
isBoundariesCollision = (x, y, drawObject) => {
const drawObjectType = drawObject.type,
vertices = drawObject.vertices,
circleBoundaries = drawObject.circleBoundaries;
switch(drawObjectType) {
case CONST.DRAW_TYPE.TEXT:
case CONST.DRAW_TYPE.RECTANGLE:
case CONST.DRAW_TYPE.CONUS:
case CONST.DRAW_TYPE.IMAGE:
if (!circleBoundaries) {
return this.#isPolygonToBoundariesCollision(x, y, vertices, drawObject.rotation);
} else {
return this.#isCircleToBoundariesCollision(x, y, drawObject.circleBoundaries.r);
}
case CONST.DRAW_TYPE.CIRCLE:
Warning(CONST.WARNING_CODES.METHOD_NOT_IMPLEMENTED, "isObjectCollision.circle check is not implemented yet!");
break;
case CONST.DRAW_TYPE.LINE:
Warning(CONST.WARNING_CODES.METHOD_NOT_IMPLEMENTED, "isObjectCollision.line check is not implemented yet, please use .rect instead line!");
break;
default:
Warning(CONST.WARNING_CODES.UNKNOWN_DRAW_OBJECT, "unknown object type!");
}
return false;
};
/**
*
* @param {number} x
* @param {number} y
* @param {DrawImageObject} drawObject
* @param {Array<DrawImageObject>} objects - objects array to check
* @returns {{x:number, y:number, p:number} | boolean} - the closest collision
*/
isObjectsCollision = (x, y, drawObject, objects) => {
const drawObjectType = drawObject.type,
drawObjectBoundaries = drawObject.vertices,
circleBoundaries = drawObject.circleBoundaries;
switch(drawObjectType) {
case CONST.DRAW_TYPE.TEXT:
case CONST.DRAW_TYPE.RECTANGLE:
case CONST.DRAW_TYPE.CONUS:
case CONST.DRAW_TYPE.IMAGE:
if (!circleBoundaries) {
return this.#isPolygonToObjectsCollision(x, y, drawObjectBoundaries, drawObject.rotation, objects);
} else {
return this.#isCircleToObjectsCollision(x, y, circleBoundaries, objects);
}
case CONST.DRAW_TYPE.CIRCLE:
Warning(CONST.WARNING_CODES.METHOD_NOT_IMPLEMENTED, "isObjectCollision.circle check is not implemented yet!");
break;
case CONST.DRAW_TYPE.LINE:
Warning(CONST.WARNING_CODES.METHOD_NOT_IMPLEMENTED, "isObjectCollision.line check is not implemented yet, please use .rect instead line!");
break;
default:
Warning(CONST.WARNING_CODES.UNKNOWN_DRAW_OBJECT, "unknown object type!");
}
return false;
};
#isPolygonToObjectsCollision(x, y, polygonVertices, polygonRotation, objects) {
const len = objects.length;
let collisions = [];
for (let i = 0; i < len; i++) {
const mapObject = objects[i],
drawMapObjectType = mapObject.type;
let coll;
switch(drawMapObjectType) {
case CONST.DRAW_TYPE.TEXT:
case CONST.DRAW_TYPE.RECTANGLE:
case CONST.DRAW_TYPE.CONUS:
case CONST.DRAW_TYPE.IMAGE:
coll = this.#isPolygonToPolygonCollision(x, y, polygonVertices, polygonRotation, mapObject);
break;
case CONST.DRAW_TYPE.CIRCLE:
console.warn("isObjectCollision.circle check is not implemented yet!");
break;
case CONST.DRAW_TYPE.LINE:
console.warn("isObjectCollision.line check is not implemented, please use rect instead");
break;
default:
console.warn("unknown object type!");
}
if (coll) {
collisions.push(coll);
}
}
if (collisions.length > 0) {
return this.#takeTheClosestCollision(collisions);
} else {
return null;
}
}
#isCircleToObjectsCollision(x, y, drawObjectBoundaries, objects) {
const radius = drawObjectBoundaries.r;
const len = objects.length;
let collisions = [];
for (let i = 0; i < len; i++) {
const mapObject = objects[i],
drawMapObjectType = mapObject.type,
circleBoundaries = mapObject.circleBoundaries;
let coll;
switch(drawMapObjectType) {
case CONST.DRAW_TYPE.TEXT:
case CONST.DRAW_TYPE.RECTANGLE:
case CONST.DRAW_TYPE.CONUS:
case CONST.DRAW_TYPE.IMAGE:
if (!circleBoundaries) {
coll = this.#isCircleToPolygonCollision(x, y, radius, mapObject);
} else {
coll = this.#isCircleToCircleCollision(x, y, radius, mapObject.x, mapObject.y, circleBoundaries.r);
}
break;
case CONST.DRAW_TYPE.CIRCLE:
console.warn("isObjectCollision.circle check is not implemented yet!");
break;
case CONST.DRAW_TYPE.LINE:
console.warn("isObjectCollision.line check is not implemented, please use rect instead");
break;
default:
console.warn("unknown object type!");
}
if (coll) {
collisions.push(coll);
}
}
if (collisions.length > 0) {
return this.#takeTheClosestCollision(collisions);
} else {
return null;
}
}
#takeTheClosestCollision(collisions) {
return collisions.sort((a,b) => a.p < b.p)[0];
}
#isCircleToPolygonCollision(x, y, radius, mapObject) {
const [mapOffsetX, mapOffsetY] = this.screenPageData.worldOffset,
xWithOffset = x - mapOffsetX,
yWithOffset = y - mapOffsetY,
mapObjXWithOffset = mapObject.x - mapOffsetX,
mapObjYWithOffset = mapObject.y - mapOffsetY,
mapObjVertices = mapObject.vertices,
mapObjRotation = mapObject.rotation,
len = mapObjVertices.length;
//console.log("map object check:");
//console.log(mapObject);
for (let i = 0; i < len; i+=1) {
const mapObjFirstVertex = mapObjVertices[i];
let mapObjNextVertex = mapObjVertices[i + 1];
if (!mapObjNextVertex) {
mapObjNextVertex = mapObjVertices[0];
}
const vertex = this.#calculateShiftedVertexPos(mapObjFirstVertex, mapObjXWithOffset, mapObjYWithOffset, mapObjRotation),
nextVertex = this.#calculateShiftedVertexPos(mapObjNextVertex, mapObjXWithOffset, mapObjYWithOffset, mapObjRotation),
edge = {
x1: vertex[0],
y1: vertex[1],
x2: nextVertex[0],
y2: nextVertex[1]
},
intersect = isCircleLineIntersect(xWithOffset, yWithOffset, radius, edge);
if (intersect) {
//console.log("polygon: ", polygonWithOffsetAndRotation);
//console.log("intersect: ", intersect);
return intersect;
}
}
return false;
}
#isCircleToCircleCollision(circle1X, circle1Y, circle1R, circle2X, circle2Y, circle2R) {
const len = new Vector(circle1X, circle1Y, circle2X, circle2Y).length;
console.log(len);
console.log(circle1R);
console.log(circle2R);
if ((len - (circle1R + circle2R)) > 0) {
return false;
} else {
//@todo calculate point of intersect
return true;
}
}
#isPolygonToPolygonCollision(x, y, polygonVertices, polygonRotation, mapObject) {
const [mapOffsetX, mapOffsetY] = this.screenPageData.worldOffset,
xWithOffset = x - mapOffsetX,
yWithOffset = y - mapOffsetY,
mapObjXWithOffset = mapObject.x - mapOffsetX,
mapObjYWithOffset = mapObject.y - mapOffsetY,
mapObjVertices = mapObject.vertices,
mapObjRotation = mapObject.rotation,
polygonWithOffsetAndRotation = polygonVertices.map((vertex) => (this.#calculateShiftedVertexPos(vertex, xWithOffset, yWithOffset, polygonRotation))),
len = mapObjVertices.length;
//console.log("map object check:");
//console.log(mapObject);
for (let i = 0; i < len; i+=1) {
const mapObjFirstVertex = mapObjVertices[i];
let mapObjNextVertex = mapObjVertices[i + 1];
if (!mapObjNextVertex) {
mapObjNextVertex = mapObjVertices[0];
}
const vertex = this.#calculateShiftedVertexPos(mapObjFirstVertex, mapObjXWithOffset, mapObjYWithOffset, mapObjRotation),
nextVertex = this.#calculateShiftedVertexPos(mapObjNextVertex, mapObjXWithOffset, mapObjYWithOffset, mapObjRotation),
edge = {
x1: vertex[0],
y1: vertex[1],
x2: nextVertex[0],
y2: nextVertex[1]
},
intersect = isPolygonLineIntersect(polygonWithOffsetAndRotation, edge);
if (intersect) {
//console.log("polygon: ", polygonWithOffsetAndRotation);
//console.log("intersect: ", intersect);
return intersect;
}
}
return false;
}
#calculateShiftedVertexPos(vertex, centerX, centerY, rotation) {
const vector = new Vector(0, 0, vertex[0], vertex[1]),
vertexAngle = angle_2points(0, 0, vertex[0], vertex[1]),
len = vector.length;
//console.log("coords without rotation: ");
//console.log(x + vertex.x);
//console.log(y + vertex.y);
//console.log("len: ", len);
//console.log("angle: ", rotation);
const newX = centerX + (len * Math.cos(rotation + vertexAngle)),
newY = centerY + (len * Math.sin(rotation + vertexAngle));
return [newX, newY];
}
#checkCollisions(renderObjects) {
const boundaries = this.screenPageData.getBoundaries(),
boundariesLen = boundaries.length,
objectsLen = renderObjects.length;
//console.log(this.screenPageData.worldOffset);
for (let i = 0; i < objectsLen; i++) {
const renderObject = renderObjects[i];
for (let j = 0; j < objectsLen; j++) {
if (i === j) {
continue;
}
// const renderObjectCheck = renderObjects[j];
// check object - object collisions
}
for (let k = 0; k < boundariesLen; k+=1) {
const item = boundaries[k],
object = {
x1: item[0],
y1: item[1],
x2: item[2],
y2: item[3]
};
const objectBoundaries = object.boundaries;
if (objectBoundaries) {
if (isPolygonLineIntersect(objectBoundaries, object)) {
this.emit(CONST.EVENTS.GAME.BOUNDARIES_COLLISION, renderObject);
}
} else {
if (isPointLineIntersect({ x: renderObject.x, y: renderObject.y }, object)) {
this.emit(CONST.EVENTS.GAME.BOUNDARIES_COLLISION, renderObject);
console.log("boundaries collision detected");
}
}
}
}
}
#isCircleToBoundariesCollision(x, y, r) {
const mapObjects = this.screenPageData.getBoundaries(),
[mapOffsetX, mapOffsetY] = this.screenPageData.worldOffset,
xWithOffset = x - mapOffsetX,
yWithOffset = y - mapOffsetY,
len = mapObjects.length;
for (let i = 0; i < len; i+=1) {
const item = mapObjects[i];
const object = {
x1: item[0],
y1: item[1],
x2: item[2],
y2: item[3]
},
intersect = isCircleLineIntersect(xWithOffset, yWithOffset, r, object);
if (intersect) {
//console.log("rotation: ", rotation);
//console.log("polygon: ", polygonWithOffsetAndRotation);
console.log("intersect: ", intersect);
return intersect;
}
}
return false;
}
/**
* @param {number} x
* @param {number} y
* @param {Array<Array<number>>} polygon
* @param {number} rotation
* @returns {{x:number, y:number, p:number} | boolean}
*/
#isPolygonToBoundariesCollision(x, y, polygon, rotation) {
//console.log("angle: ", rotation);
//console.log("boundaries before calculations: ");
//console.log(polygon);
const mapObjects = this.screenPageData.getBoundaries(),
[mapOffsetX, mapOffsetY] = this.screenPageData.worldOffset,
xWithOffset = x - mapOffsetX,
yWithOffset = y - mapOffsetY,
polygonWithOffsetAndRotation = polygon.map((vertex) => (this.#calculateShiftedVertexPos(vertex, xWithOffset, yWithOffset, rotation))),
len = mapObjects.length;
for (let i = 0; i < len; i+=1) {
const item = mapObjects[i];
const object = {
x1: item[0],
y1: item[1],
x2: item[2],
y2: item[3]
},
intersect = isPolygonLineIntersect(polygonWithOffsetAndRotation, object);
if (intersect) {
//console.log("rotation: ", rotation);
//console.log("polygon: ", polygonWithOffsetAndRotation);
//console.log("intersect: ", intersect);
return intersect;
}
}
return false;
}
//****************** End Collisions ****************//
#setCanvasSize() {
const canvasWidth = this.systemSettings.canvasMaxSize.width && (this.systemSettings.canvasMaxSize.width < window.innerWidth) ? this.systemSettings.canvasMaxSize.width : window.innerWidth,
canvasHeight = this.systemSettings.canvasMaxSize.height && (this.systemSettings.canvasMaxSize.height < window.innerHeight) ? this.systemSettings.canvasMaxSize.height : window.innerHeight;
this.screenPageData._setCanvasDimensions(canvasWidth, canvasHeight);
this.#renderInterface.setCanvasSize(canvasWidth, canvasHeight)
//for (const view of this.#views.values()) {
// view._setCanvasSize(canvasWidth, canvasHeight);
//}
}
#countFPSaverage() {
const timeLeft = this.systemSettings.gameOptions.render.averageFPStime,
steps = this.#tempFPStime.length;
let fullTime = 0;
for(let i = 0; i < steps; i++) {
const timeStep = this.#tempFPStime[i];
fullTime += timeStep;
}
console.log("FPS average for ", timeLeft/1000, "sec, is ", fullTime / steps);
// cleanup
this.#tempFPStime = [];
}
#render = async (/*time*/) => {
Logger.debug("_render " + this.name + " class");
if (this.#isActive) {
switch (this.systemSettings.gameOptions.library) {
case CONST.LIBRARY.WEBGL:
if (this.isAllFilesLoaded()) {
//render
await this.#prepareViews();
} else {
Warning(WARNING_CODES.ASSETS_NOT_READY, "Is page initialization phase missed?");
this.#isActive = false;
}
// wait for the end of the execution stack, before start next iteration
setTimeout(() => requestAnimationFrame(this.#drawViews));
break;
}
this.#fpsAverageCountTimer = setInterval(() => this.#countFPSaverage(), this.systemSettings.gameOptions.render.averageFPStime);
}
};
/**
*
* @returns {Promise<void>}
*/
#prepareViews() {
return new Promise((resolve, reject) => {
let viewPromises = [];
const isBoundariesPrecalculations = this.#isBoundariesPrecalculations;
viewPromises.push(this.#renderInterface.initiateContext());
if (isBoundariesPrecalculations) {
console.warn("isBoundariesPrecalculations() is turned off");
//for (const view of this.#views.values()) {
//viewPromises.push(this.#renderInterface._createBoundariesPrecalculations());
//}
}
if (this.systemSettings.gameOptions.optimization === CONST.OPTIMIZATION.WEB_ASSEMBLY.WASM) {
viewPromises.push(this.#renderInterface.initiateWasm());
}
Promise.allSettled(viewPromises).then((drawingResults) => {
drawingResults.forEach((result) => {
if (result.status === "rejected") {
const error = result.reason;
Warning(WARNING_CODES.UNHANDLED_DRAW_ISSUE, error);
reject(error);
}
});
resolve();
});
});
}
#drawViews = async (/*drawTime*/) => {
const pt0 = performance.now(),
minCircleTime = this.#minCircleTime;
let viewPromises = [];
this.emit(CONST.EVENTS.SYSTEM.RENDER.START);
this.screenPageData._clearBoundaries();
this.#renderInterface.clearContext();
//for (const [key, view] of this.#views.entries()) {
// const render = await view.render(key);
// viewPromises.push(render);
//}
const render = await this.#renderInterface.render();
viewPromises.push(render);
Promise.allSettled(viewPromises).then((drawingResults) => {
drawingResults.forEach((result) => {
if (result.status === "rejected") {
Warning(WARNING_CODES.UNHANDLED_DRAW_ISSUE, result.reason);
this.#isActive = false;
}
});
const r_time = performance.now() - pt0,
r_time_less = minCircleTime - r_time,
wait_time = r_time_less > 0 ? r_time_less : 0,
fps = 1000 / (r_time + wait_time);
//console.log("draw circle done, take: ", (r_time), " ms");
//console.log("fps: ", fps);
this.emit(CONST.EVENTS.SYSTEM.RENDER.END);
if(fps === Infinity) {
console.log("infinity time");
}
this.#tempFPStime.push(fps);
if (this.#isActive) {
setTimeout(() => requestAnimationFrame(this.#drawViews), wait_time);
}
});
};
}