@urso/core
Version:
HTML5 game engine
1,499 lines • 2.95 MB
JavaScript
var __defProp = Object.defineProperty;
var __typeError = (msg) => {
throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var _a, _vocabulary;
class ComponentsBaseController {
constructor(options) {
this._templateName = "Template";
this._inputValidation(options);
this.common = {
find: null,
//find functions inside component object in scene
findAll: null,
findOne: null,
object: null
//link to component object in scene
};
this.options = options;
}
/**
* function for the component input params validation
* must return as a result input structure
* @returns {object}
* @example
* return {
* param1Name: 'number',
* param2Name: 'string'
* }
*/
_requiredOptionsModel() {
}
_inputValidation(options) {
let optionsModel = this._requiredOptionsModel();
if (optionsModel)
for (let optionKey in optionsModel) {
if (!options || typeof options[optionKey] !== optionsModel[optionKey])
Urso.logger.error("Component params model error", this);
}
}
loadUpdate() {
}
assetsMount() {
let template = this.getInstance(this._templateName, this.options);
return { styles: template.styles, assets: template.assets };
}
objectsMount() {
let template = this.getInstance(this._templateName, this.options);
return template.objects;
}
create() {
}
/**
* @param {Number} deltaTime - time from last update call
*/
update(deltaTime) {
}
_subscribeOnce() {
}
destroy() {
}
}
class ComponentsDebugController extends ComponentsBaseController {
constructor(params) {
super(params);
this._logicBlocks = [
"coords",
"fps",
"timescale"
/*'renderStats', 'resolution'*/
//TODO
];
this._visible = true;
this._comObject = false;
this._created;
}
create() {
this._created = true;
this._comObject = this.common.findOne("^debugContainer");
this._show(true);
Urso.helper.logicBlocksDo(this, "create");
return true;
}
update() {
if (!this._created)
return;
Urso.helper.logicBlocksDo(this, "update");
}
_show(visMode) {
this._visible = typeof visMode !== "undefined" ? visMode : !this._visible;
this._comObject.visible = this._visible;
}
}
class ComponentsDebugCoords {
constructor() {
this._coordsText;
this.create = this.create.bind(this);
this.update = this.update.bind(this);
}
create() {
this._coordsText = this.common.findOne("^debugCoords");
this.update();
return true;
}
update() {
let coords = Urso.scenes.getMouseCoords();
this._coordsText.text = "x:" + Math.floor(coords.x) + "; y:" + Math.floor(coords.y);
}
}
class ComponentsDebugFps {
constructor() {
this._coordsText;
this.create = this.create.bind(this);
this.update = this.update.bind(this);
this.lastUpdateTime = 0;
this.frames = 0;
}
create() {
this._coordsText = this.common.findOne("^debugFps");
this.update();
return true;
}
update() {
const currentTime = Urso.time.get();
this.frames++;
if (currentTime - this.lastUpdateTime < 1e3)
return;
const fps = Math.round(1e3 * this.frames / (currentTime - this.lastUpdateTime));
this.lastUpdateTime = currentTime;
this.frames = 0;
const fpsData = Urso.scenes.getFpsData();
this._coordsText.text = `fps: ${fps}, sceneFps: ${fpsData.fps}, limit: ${fpsData.limit}`;
}
}
class ComponentsDebugTemplate {
constructor() {
this.objects = [
{
type: Urso.types.objects.CONTAINER,
name: "debugContainer",
contents: [
{
type: Urso.types.objects.TEXT,
name: "debugCoords",
text: "x:0, y:0",
fontFamily: "Helvetica",
fontSize: 30,
fill: "#00FF00"
},
{
type: Urso.types.objects.TEXT,
name: "debugFps",
text: "fps: 0",
y: 30,
fontFamily: "Helvetica",
fontSize: 30,
fill: "#00FF00"
},
{
type: Urso.types.objects.TEXT,
name: "debugTimescaleValue",
text: "1",
x: "50%",
y: "30%",
visible: false,
anchorX: 0.5,
anchorY: 0.5,
fontFamily: "Verdana",
fontSize: 100,
fontStyle: "italic",
fontWeight: "bold",
fill: ["#ffffff", "#00ff99"],
// gradient
stroke: "#4a1850",
strokeThickness: 5,
dropShadow: true,
dropShadowColor: "#000000",
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6
}
]
}
];
}
}
class ComponentsDebugTimescale {
constructor() {
this._timescaleText;
this.create = this.create.bind(this);
this.scaleStep = 0.5;
this.scaleInfoDuration = 2e3;
this._minusButtonsCodes = [109, 189];
this._plusButtonsCodes = [107, 187];
this._hideId;
}
create() {
document.addEventListener("keydown", this.keyPressTest.bind(this));
this._timescaleText = this.common.findOne("^debugTimescaleValue");
return true;
}
keyPressTest(e2) {
const evtobj = window.event ? event : e2;
if (!evtobj.altKey)
return;
let factor = 0;
if (this._minusButtonsCodes.includes(evtobj.keyCode)) {
factor = -1;
}
if (this._plusButtonsCodes.includes(evtobj.keyCode)) {
factor = 1;
}
if (!factor)
return;
const timescaleDiff = Urso.scenes.timeScale >= 1 ? this.scaleStep * factor : this.scaleStep * factor * 0.1;
let timescaleNewValue = Urso.scenes.timeScale + timescaleDiff;
if (timescaleNewValue < 0.1)
timescaleNewValue = 0.1;
Urso.scenes.timeScale = Urso.math.roundToDigits(timescaleNewValue, 2);
this._timescaleText.text = Urso.scenes.timeScale;
this._timescaleText.visible = true;
if (this._hideId)
clearTimeout(this._hideId);
this._hideId = setTimeout(() => this._timescaleText.visible = false, this.scaleInfoDuration);
}
}
class ComponentsDeviceRotateController extends ComponentsBaseController {
constructor(params) {
super(params);
this._created = false;
this._div = null;
this._orientation = null;
this._resolutionsConfig = null;
}
create() {
if (Urso.device.desktop)
return;
this._resolutionsConfig = Urso.getInstance("Modules.Scenes.ResolutionsConfig").contents || [];
this._createDom();
this._updateOrientation();
this._updateVisibility();
this._created = true;
}
_createDom() {
this._div = document.createElement("div");
this._div.className = "fullscreen device-rotate";
this._div.style.touchAction = "none";
this._div.style.visibility = "hidden";
document.body.prepend(this._div);
const infoDiv = document.createElement("div");
infoDiv.className = "fullscreen-info";
this._div.appendChild(infoDiv);
const image = document.createElement("img");
image.src = `${Urso.config.gamePath}assets/images/fullscreen/rotate.png`;
const span = document.createElement("span");
span.innerText = "Please rotate device";
infoDiv.appendChild(image);
infoDiv.appendChild(span);
}
get _showOnLandscape() {
if (!this._resolutionsConfig) return false;
return !this._resolutionsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.LANDSCAPE);
}
get _showOnPortrait() {
if (!this._resolutionsConfig) return false;
return !this._resolutionsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.PORTRAIT);
}
get _isPortrait() {
return this._orientation === Urso.device.ScreenOrientation.PORTRAIT;
}
get _needShow() {
return this._orientation === Urso.device.ScreenOrientation.PORTRAIT && this._showOnPortrait || this._orientation !== Urso.device.ScreenOrientation.PORTRAIT && this._showOnLandscape;
}
set _isVisible(needShowDiv) {
this._div.style.visibility = needShowDiv ? "visible" : "hidden";
}
_updateOrientation() {
this._orientation = innerWidth > innerHeight ? Urso.device.ScreenOrientation.LANDSCAPE : Urso.device.ScreenOrientation.PORTRAIT;
}
_updateVisibility() {
this._isVisible = this._needShow;
}
_resizeHandler() {
if (!this._created)
return;
this._updateOrientation();
this._updateVisibility();
}
_subscribeOnce() {
if (Urso.device.desktop)
return;
this.addListener(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE, this._resizeHandler.bind(this));
}
}
class ComponentsEditorController extends ComponentsBaseController {
constructor(params) {
super(params);
this._api = this.getInstance("Api");
Urso.helper.recursiveSet("_dev.editorApi", this._api, Urso);
}
}
class ComponentsEditorApi {
constructor() {
//////////////// sys
__publicField(this, "_assetsKeys", {
ATLAS: [{ name: "key", type: "text" }, { name: "path", type: "file" }],
// path to json file
BITMAPFONT: [{ name: "key", type: "text" }, { name: "path", type: "file" }],
// path to json file
CONTAINER: [{ name: "key", type: "text" }],
FONT: [{ name: "key", type: "text" }, { name: "path", type: "file" }],
// path to json file
IMAGE: [{ name: "key", type: "text" }, { name: "path", type: "file" }],
// path to json file
JSON: [{ name: "key", type: "text" }, { name: "path", type: "file" }],
// path to json file
SPINE: [{ name: "key", type: "text" }, { name: "path", type: "file" }]
// path to json file
});
__publicField(this, "_commonObjectsKeys", [
{ name: "id", type: "text" },
{ name: "name", type: "text" },
{ name: "class", type: "text" },
{ name: "x", type: "number" },
{ name: "y", type: "number" },
{ name: "z", type: "number" },
{ name: "anchorX", type: "number", range: [-1, 1] },
{ name: "anchorY", type: "number", range: [-1, 1] },
{ name: "scaleX", type: "number" },
{ name: "scaleY", type: "number" },
{ name: "angle", type: "number", range: [0, 360] },
{ name: "alpha", type: "number", range: [0, 1] },
{ name: "visible", type: "boolean" }
]);
__publicField(this, "_objectsKeys", {
BITMAPTEXT: Urso.helper.mergeArrays(this._commonObjectsKeys, [{ name: "text", type: "text" }, { name: "fontName", type: "text" }, { name: "fontSize", type: "text" }]),
COMPONENT: Urso.helper.mergeArrays(this._commonObjectsKeys, [{ name: "componentName", type: "text" }]),
CONTAINER: this._commonObjectsKeys,
GROUP: Urso.helper.mergeArrays(this._commonObjectsKeys, [{ name: "groupName", type: "text" }]),
IMAGE: Urso.helper.mergeArrays(this._commonObjectsKeys, [{ name: "assetKey", type: "text" }]),
TEXT: Urso.helper.mergeArrays(this._commonObjectsKeys, [
{ name: "text", type: "text" },
{ name: "fontFamily", type: "text" },
{ name: "fontSize", type: "text" },
{ name: "fill", type: "text" },
{ name: "stroke", type: "text" }
])
});
}
//styles
//TODO
addStyle() {
}
getCurrentStyles() {
const template = Urso.template.get();
return template.styles;
}
//assets
/**
* returns types list and keys to create new asset
* @returns { types, keys }
*/
getAssetTypes() {
const types = Urso.types.assets;
return { types, keys: this._assetsKeys };
}
/**
* get current assets list
* @returns {Array} assets list
*/
getCurrentAssets() {
const template = Urso.template.get();
return template.assets;
}
/**
* add new asset into game
* @param {String} assetModel
* @param {Function} callback
*/
addAsset(assetModel, callback) {
Urso.assets.preload([assetModel], callback);
}
//objects
/**
* get current objects list
* @returns {Array} objects list
*/
getCurrentObjects() {
const template = Urso.template.get();
return template.objects;
}
/**
* returns types list and keys to create new object
* @returns { types, keys }
*/
getObjectsTypes() {
const types = Urso.types.objects;
return { types, keys: this._objectsKeys };
}
/**
* add new object into game
* @param {Object} objectModel
* @param {Object} parent
*/
addObject(objectModel, parent) {
Urso.objects.create(objectModel, parent);
}
//settings
editObject(id, key, value) {
}
}
class ComponentsFullscreenAndroid {
constructor() {
this._div = null;
this._orientation = null;
}
init() {
this._createDom();
this._addListeners();
this._updateOrientation();
this._updateResize();
}
_createDom() {
this._div = document.createElement("div");
this._div.className = "fullscreen fullscreen-android";
document.body.prepend(this._div);
const infoDiv = document.createElement("div");
infoDiv.className = "fullscreen-info";
this._div.appendChild(infoDiv);
const image = document.createElement("img");
image.src = `${Urso.config.gamePath}assets/images/fullscreen/hand.png`;
const span = document.createElement("span");
span.innerText = "Tap to enter fullscreen";
infoDiv.appendChild(image);
infoDiv.appendChild(span);
}
_updateOrientation() {
this._orientation = innerWidth > innerHeight ? Urso.device.ScreenOrientation.LANDSCAPE : Urso.device.ScreenOrientation.PORTRAIT;
}
get isFullscreen() {
return document.webkitIsFullScreen || document.mozFullScreen || document.fullscreen;
}
get _orientationsConfig() {
return Urso.getInstance("Modules.Scenes.ResolutionsConfig").contents || [];
}
get _isPortrait() {
return this._orientation === Urso.device.ScreenOrientation.PORTRAIT;
}
get _needShowOnCurrentOrientation() {
return this._isPortrait && this._showOnPortrait || !this._isPortrait && this._showOnLandscape;
}
get _showOnLandscape() {
return this._orientationsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.LANDSCAPE);
}
get _showOnPortrait() {
return this._orientationsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.PORTRAIT);
}
set isVisible(needShowDiv) {
this._div.style.visibility = needShowDiv ? "visible" : "hidden";
}
_requestFullscreen() {
if (document.body.webkitRequestFullScreen)
document.body.webkitRequestFullScreen();
else if (document.body.mozRequestFullScreen)
document.body.mozRequestFullScreen();
else if (document.body.requestFullScreen)
document.body.requestFullScreen();
}
_updateResize() {
this.isVisible = this._needShowOnCurrentOrientation && !this.isFullscreen;
}
_resizeHandler() {
this._updateOrientation();
this._updateResize();
}
_addListeners() {
window.addEventListener("touchend", (e2) => {
if (!this.isFullscreen)
this._requestFullscreen();
this._updateResize();
});
}
_subscribeOnce() {
this.addListener(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE, this._resizeHandler.bind(this));
}
}
class ComponentsFullscreenController extends ComponentsBaseController {
constructor(params) {
super(params);
this._fullscreenActivator = null;
this._resolutionsConfig = null;
this.lastResizeFullscreenResult;
this.createActivator();
this._resizeHandler();
}
createActivator() {
if (this._isCriOS)
return;
this._resolutionsConfig = Urso.getInstance("Modules.Scenes.ResolutionsConfig").contents || [];
if (Urso.device.desktop)
this._fullscreenActivator = this.getInstance("Desktop");
else if (Urso.device.iOS)
this._fullscreenActivator = this.getInstance("Ios");
else if (Urso.device.android)
this._fullscreenActivator = this.getInstance("Android");
if (this._fullscreenActivator)
this._fullscreenActivator.init();
}
get _isCriOS() {
return navigator.userAgent.includes("CriOS");
}
get _orientationsConfig() {
return Urso.getInstance("Modules.Scenes.ResolutionsConfig")._orientations || [];
}
get _showOnLandscape() {
return this._resolutionsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.LANDSCAPE);
}
get _showOnPortrait() {
return this._resolutionsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.PORTRAIT);
}
get _isPortrait() {
return innerWidth > innerHeight ? Urso.device.ScreenOrientation.PORTRAIT : Urso.device.ScreenOrientation.LANDSCAPE;
}
get isFullscreen() {
if (!this._fullscreenActivator)
return false;
return this._fullscreenActivator.isFullscreen;
}
_resizeHandler() {
const isFullscreen = this.isFullscreen;
if (this.lastResizeFullscreenResult === isFullscreen)
return;
this.lastResizeFullscreenResult = isFullscreen;
Urso.localData.set("fullscreen.isFullscreen", isFullscreen);
this.emit(Urso.events.COMPONENTS_FULLSCREEN_CHANGE, isFullscreen);
}
_subscribeOnce() {
this.addListener(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE, this._resizeHandler.bind(this));
}
}
class ComponentsFullscreenDesktop {
init() {
}
get isFullscreen() {
return document.webkitIsFullScreen || document.mozFullScreen || document.fullscreen;
}
_requestFullscreen() {
if (document.body.webkitRequestFullScreen)
document.body.webkitRequestFullScreen();
else if (document.body.mozRequestFullScreen)
document.body.mozRequestFullScreen();
else if (document.body.requestFullScreen)
document.body.requestFullScreen();
}
_cancelFullscreen() {
if (document.webkitCancelFullScreen)
document.webkitCancelFullScreen();
else if (document.mozCancelFullScreen)
document.mozCancelFullScreen();
else if (document.cancelFullScreen)
document.cancelFullScreen();
}
_switchFullscreen(needGoFullscreen = null) {
if (needGoFullscreen === null)
needGoFullscreen = !this.isFullscreen;
if (needGoFullscreen)
this._requestFullscreen();
else
this._cancelFullscreen();
}
_fullscreenSwitchHandler(needGoFullscreen = null) {
this._switchFullscreen(needGoFullscreen);
}
_subscribeOnce() {
this.addListener(Urso.events.COMPONENTS_FULLSCREEN_SWITCH, this._fullscreenSwitchHandler.bind(this));
}
}
class ComponentsFullscreenIos {
constructor() {
this._div = null;
this._orientation = null;
this._scrollTimeout = null;
}
init() {
this._createDom();
this._addListeners();
this._updateResize();
}
_createDom() {
this._div = document.createElement("div");
this._div.className = "fullscreen fullscreen-ios";
document.body.prepend(this._div);
const infoDiv = document.createElement("div");
infoDiv.className = "fullscreen-info";
this._div.appendChild(infoDiv);
const image = document.createElement("img");
image.src = `${Urso.config.gamePath}assets/images/fullscreen/scroll.png`;
const span = document.createElement("span");
span.innerText = "Swipe up to enter fullscreen";
infoDiv.appendChild(image);
infoDiv.appendChild(span);
}
_addListeners() {
window.addEventListener("touchmove", (e2) => {
this._updateResize();
if (e2.touches.length > 1) {
e2.preventDefault();
return;
}
});
}
get isFullscreen() {
return this._isFullscreen;
}
get _isFullscreen() {
const minFactor = 0.51;
const deviceFactor = screen.width / screen.height;
const factor = this._isPortrait ? innerWidth / innerHeight : innerHeight / innerWidth;
return !(this._isPortrait ? factor - deviceFactor < 0.1 : factor > minFactor);
}
_updateOrientation() {
this._orientation = innerWidth > innerHeight ? Urso.device.ScreenOrientation.LANDSCAPE : Urso.device.ScreenOrientation.PORTRAIT;
}
_updateResize() {
this._updateOrientation();
this.isVisible = this._needShowOnCurrentOrientation && this._isFullscreen;
}
get _orientationsConfig() {
return Urso.getInstance("Modules.Scenes.ResolutionsConfig").contents || [];
}
get _isPortrait() {
return this._orientation === Urso.device.ScreenOrientation.PORTRAIT;
}
get _needShowOnCurrentOrientation() {
return this._isPortrait && this._showOnPortrait || !this._isPortrait && this._showOnLandscape;
}
get _showOnLandscape() {
return this._orientationsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.LANDSCAPE);
}
get _showOnPortrait() {
return this._orientationsConfig.find((resolution) => resolution.orientation === Urso.device.ScreenOrientation.PORTRAIT);
}
set isVisible(needShowDiv) {
this._div.style.zIndex = needShowDiv ? 1 : -1;
clearTimeout(this._scrollTimeout);
this._scrollTimeout = setTimeout(() => {
if (needShowDiv)
window.scrollTo(0, 0);
}, 200);
}
_resizeHandler() {
this._updateResize();
}
_fullscreenSwitchHandler(needGoFullscreen = null) {
this._switchFullscreen(needGoFullscreen);
}
_subscribeOnce() {
this.addListener(
Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE,
this._resizeHandler.bind(this)
);
}
}
class ComponentsLayersSwitcherController extends ComponentsBaseController {
constructor(...args) {
super(...args);
this._config = this.getInstance("Config");
}
/**
* disable all layers from the list of managed layers (config.allLayers) and enables layers corresponding to the desired group (config.groupsLayers[groupName])
* @param {String} groupName
*/
_showGroup(groupName) {
const configLayersGroup = this._config.groupsLayers[groupName];
if (configLayersGroup) {
this._config.allLayers.forEach((selectorLayers) => {
const layerVisibleStatus = configLayersGroup.includes(selectorLayers) ? true : false;
Urso.findAll(selectorLayers).forEach((selectorObject) => {
selectorObject.visible = layerVisibleStatus;
});
});
} else {
Urso.logger.error(`ComponentsLayersSwitcherController: group '${groupName}' was not found!`);
}
}
_subscribeOnce() {
this.addListener(Urso.events.COMPONENTS_LAYERS_SWITCHER_SWITCH, (groupName) => {
this._showGroup(groupName);
});
}
}
class ComponentsLayersSwitcher {
constructor() {
this.allLayers = [
"^granny",
"^mainButton",
"^logo",
".backround",
"^bonusPopup",
".baseGame",
".bonusGame"
];
this.groupsLayers = {
"mainElements": ["^logo", "^mainButton", ".baseGame"],
"background": [".backround"],
"granny": ["^granny"],
"bonusGame": [".bonusGame", "^bonusPopup"]
};
}
}
class ComponentsLoaderController extends ComponentsBaseController {
loadUpdate(loadProgress) {
this.setLoadProgress(loadProgress);
}
create() {
this.setMask();
}
setMask() {
if (this.loaderBg && this.loaderBgMask)
this.loaderBg._baseObject.mask = this.loaderBgMask._baseObject;
}
formatAmountText(text) {
return `${text}%`;
}
setLoadProgress(val) {
if (!this.componentCreated) return;
this.loaderBgMask._baseObject.scale.x = val;
this.loadAmountText.text = this.formatAmountText(val);
}
get componentCreated() {
return !!this.loadAmountText && !!this.loaderBg && !!this.loaderBgMask;
}
get loadAmountText() {
return Urso.findOne(".loadAmountText");
}
get loaderBg() {
return Urso.findOne("^loaderBg");
}
get loaderBgMask() {
return Urso.findOne("^loaderBgMask");
}
}
class ComponentsLoaderTemplate {
constructor() {
this.styles = {
".loadingTextStyle": {
fill: 16777215,
fontSize: 32,
fontWeight: "bold",
fontStyle: "italic"
}
};
this.assets = [];
this.objects = [
// {
// type: Urso.types.objects.GRAPHICS,
// x: 100,
// y: 100,
// name: 'qqqq',
// figure: {
// rectangle: [0, 0, 100, 100],
// fillColor: 0x66f542
// }
// },
// {
// type: Urso.types.objects.CONTAINER,
// name: 'loaderContainer',
// visible: false,
// contents: [
// {
// type: Urso.types.objects.GRAPHICS,
// name: 'bgLoader',
// figure: {
// rectangle: [0, 20, 500, 20],
// fillColor: 0x66f542
// }
// },
// {
// type: Urso.types.objects.CONTAINER,
// contents: [
// {
// type: Urso.types.objects.GRAPHICS,
// figure: {
// rectangle: [4, 24, 492, 13],
// }
// },
// {
// type: Urso.types.objects.GRAPHICS,
// name: 'loaderBg',
// figure: {
// rectangle: [4, 24, 492, 13],
// fillColor: 0x66f542
// }
// },
// {
// type: Urso.types.objects.GRAPHICS,
// name: 'loaderBgMask',
// figure: {
// rectangle: [4, 24, 492, 13]
// }
// },
// {
// type: Urso.types.objects.CONTAINER,
// x: 260,
// y: 50,
// contents: [
// {
// type: Urso.types.objects.TEXT,
// class: 'loadingTextStyle loadAmountText',
// anchorX: 0.5,
// text: '100%'
// }
// ]
// }
// ]
// }
// ]
// }
];
}
}
class ComponentsSoundInitialPopupController extends ComponentsBaseController {
constructor() {
super();
this.yesButton = null;
this.noButton = null;
}
create() {
this.yesButton = this.common.findOne("^soundInitialPopupButtonYesGraphics");
this.noButton = this.common.findOne("^soundInitialPopupButtonNoGraphics");
}
_tintHandler({ buttonName, pointerOver }) {
let button = buttonName === "yes" ? this.yesButton : this.noButton;
button._baseObject.tint = pointerOver ? 13942377 : 16777215;
}
_buttonPressHandler({ name }) {
switch (name) {
case "soundInitialPopupButtonYesHit":
this.emit(Urso.events.MODULES_SOUND_MANAGER_SET_GLOBAL_VOLUME, 1);
break;
case "soundInitialPopupButtonNoHit":
this.emit(Urso.events.MODULES_SOUND_MANAGER_SET_GLOBAL_VOLUME, 0);
break;
default:
return;
}
this.common.object.visible = false;
}
_subscribeOnce() {
this.addListener("components.soundInitialPopup.pointerAction.popupButton", this._tintHandler.bind(this));
this.addListener(Urso.events.MODULES_OBJECTS_HIT_AREA_PRESS, this._buttonPressHandler.bind(this));
}
}
class ComponentsSoundInitialPopupTemplate {
constructor() {
this.objects = [
{
type: Urso.types.objects.HITAREA,
x: -50,
y: -50,
width: 2e3,
height: 1200
},
{
type: Urso.types.objects.GRAPHICS,
figure: {
rectangle: [0, 0, 1920, 1080],
fillColor: "black"
}
},
{
type: Urso.types.objects.TEXT,
y: -100,
alignX: "center",
alignY: "center",
anchorX: 0.5,
anchorY: 0.5,
fill: "gray",
fontFamilu: "Helvetica",
fontSize: 72,
fontWeight: 800,
text: "Enable sound?"
},
{
type: Urso.types.objects.CONTAINER,
x: 600,
y: 650,
with: 200,
height: 70,
contents: [
{
type: Urso.types.objects.GRAPHICS,
name: "soundInitialPopupButtonYesGraphics",
figure: {
rectangle: [0, 0, 200, 70],
fillColor: 14199811
}
},
{
type: Urso.types.objects.TEXT,
anchorX: 0.5,
anchorY: 0.5,
x: 100,
alignY: "center",
fill: "black",
fontFamilu: "Helvetica",
fontSize: 40,
fontWeight: 800,
text: "YES"
},
{
type: Urso.types.objects.HITAREA,
name: "soundInitialPopupButtonYesHit",
width: 200,
height: 70,
onOverCallback: () => this.emit("components.soundInitialPopup.pointerAction.popupButton", { buttonName: "yes", pointerOver: true }),
onOutCallback: () => this.emit("components.soundInitialPopup.pointerAction.popupButton", { buttonName: "yes", pointerOver: false })
}
]
},
{
type: Urso.types.objects.CONTAINER,
x: 1150,
y: 650,
with: 200,
height: 70,
contents: [
{
type: Urso.types.objects.GRAPHICS,
name: "soundInitialPopupButtonNoGraphics",
figure: {
rectangle: [0, 0, 200, 70],
fillColor: 14199811
}
},
{
type: Urso.types.objects.TEXT,
anchorX: 0.5,
anchorY: 0.5,
x: 100,
alignY: "center",
fill: "black",
fontFamilu: "Helvetica",
fontSize: 40,
fontWeight: 800,
text: "NO"
},
{
type: Urso.types.objects.HITAREA,
name: "soundInitialPopupButtonNoHit",
width: 200,
height: 70,
onOverCallback: () => this.emit("components.soundInitialPopup.pointerAction.popupButton", { buttonName: "no", pointerOver: true }),
onOutCallback: () => this.emit("components.soundInitialPopup.pointerAction.popupButton", { buttonName: "no", pointerOver: false })
}
]
}
];
}
}
class ComponentsStateDrivenController extends ComponentsBaseController {
constructor() {
super(...arguments);
//config for the states guards
__publicField(this, "configStates", {
/*IDLE: {
guard: () => { log(123, 'IDLE guard'); return true; }
}*/
});
//config for the actions configs. Guard and terminate functions are optional. Run will called when action starts.
//call finish callback in the run handler to immidiately finish this action
//use this.callFinish(actionKey) when its need after run handler called to delayed finish this action
__publicField(this, "configActions", {
/*startSpin: {
guard: () => { log(123, 'guard'); return true; },
run: (finish) => { log(123, 'run'); finish(); },
terminate: () => { log(123, 'terminate'); }
}*/
});
//system callbacks storage
__publicField(this, "_finishCallbacks", {});
__publicField(this, "_callbacksCache", {
stateGuards: {},
actionTerminates: {},
actionGuards: {},
actionRuns: {}
});
}
/**
* caller for delayed finish callback
* @param {String} actionKey
*/
callFinish(actionKey) {
if (!this._finishCallbacks[actionKey]) {
Urso.logger.error("ComponentsStateDrivenController: no finish for actionKey", actionKey, this);
return;
}
this._finishCallbacks[actionKey]();
delete this._finishCallbacks[actionKey];
}
_processStates() {
for (const stateKey in this.configStates) {
this._callbacksCache.stateGuards[stateKey] = this.configStates[stateKey].guard.bind(this);
Urso.statesManager.setStateGuard(stateKey, this._callbacksCache.stateGuards[stateKey]);
}
}
_processActions() {
for (const actionKey in this.configActions) {
const actionCfg = this.configActions[actionKey];
if (actionCfg.run) {
this._callbacksCache.actionRuns[actionKey] = (finish) => {
this._saveFinish(actionKey, finish);
actionCfg.run(() => this.callFinish(actionKey));
};
Urso.statesManager.addActionRun(actionKey, this._callbacksCache.actionRuns[actionKey]);
} else {
Urso.logger.error("ComponentsStateDrivenController: no run function in config", actionKey, this);
continue;
}
if (actionCfg.terminate) {
this._callbacksCache.actionTerminates[actionKey] = actionCfg.terminate.bind(this);
Urso.statesManager.addActionTerminate(actionKey, this._callbacksCache.actionTerminates[actionKey]);
}
if (actionCfg.guard) {
this._callbacksCache.actionGuards[actionKey] = actionCfg.guard.bind(this);
Urso.statesManager.addActionGuard(actionKey, this._callbacksCache.actionGuards[actionKey]);
}
}
}
/**
* saver for delayed finish callback
* @param {String} actionKey
* @param {Function} finish
*/
_saveFinish(actionKey, finish) {
if (this._finishCallbacks[actionKey])
Urso.logger.error("ComponentsStateDrivenController: actionKey alredy exists", actionKey, finish, this);
this._finishCallbacks[actionKey] = finish;
}
_subscribeOnce() {
this._processStates();
this._processActions();
this.addListener(Urso.events.MODULES_STATES_MANAGER_STOP, this._onStatesManagerStop.bind(this), true);
}
destroy() {
this._removeCallback(Urso.statesManager.removeStateGuard, this._callbacksCache.stateGuards);
this._removeCallback(Urso.statesManager.removeActionGuard, this._callbacksCache.actionGuards);
this._removeCallback(Urso.statesManager.removeActionTerminate, this._callbacksCache.actionTerminates);
this._removeCallback(Urso.statesManager.removeActionRun, this._callbacksCache.actionRuns);
}
_removeCallback(remover, cacheObject) {
for (let cacheKey in cacheObject) {
remover(cacheKey, cacheObject[cacheKey]);
}
}
_onStatesManagerStop() {
this._finishCallbacks = {};
}
}
let ConfigMain = {
title: "Urso",
//game title
appVersion: 0,
//app version, also used as anticache "appVersion=${appVersion}" when not 0
mode: "development",
// development/production/testing
defaultLogLevel: "ERROR,WARNING,INFO,LOG",
//setup custom log level with: ?logLevel=1,2,3,4 OR ?logLevel=ERROR,WARNING,INFO,LOG
extendingChain: ["Urso.Core"],
//chain that will be set as Urso.Game
defaultScene: "play",
//default scene to display
gamePath: "",
//use assets from some gamePath directory, not from page was loaded
useBinPath: false,
// use assets from bin directory,
useTransport: false,
// use transport module for connetcting with server
fps: {
limit: 60,
//max fps limit
optimizeLowPerformance: false
//down to 30 fps if lower 60
}
};
class ExtraBrowserEvents {
constructor() {
this.singleton = true;
this.RESIZE_DELAY = 0;
this._keyPressHandler = this._keyPressHandler.bind(this);
this.resizeHandler = this.resizeHandler.bind(this);
this.visibilitychangeHandler = this.visibilitychangeHandler.bind(this);
this._pointerEventsHandler = this._pointerEventsHandler.bind(this);
this._resizeTimeoutId;
this.init();
}
init() {
window.addEventListener("keydown", this._keyPressHandler);
document.addEventListener("visibilitychange", this.visibilitychangeHandler);
window.addEventListener("resize", this.resizeHandler);
window.addEventListener("orientationchange", this.resizeHandler);
document.addEventListener("fullscreenchange", this.resizeHandler);
document.addEventListener("webkitfullscreenchange", this.resizeHandler);
document.addEventListener("mozfullscreenchange", this.resizeHandler);
document.addEventListener("mousedown", this._pointerEventsHandler);
document.addEventListener("mousemove", this._pointerEventsHandler);
document.addEventListener("mouseup", this._pointerEventsHandler);
document.addEventListener("touchstart", this._pointerEventsHandler);
document.addEventListener("touchmove", this._pointerEventsHandler);
document.addEventListener("touchend", this._pointerEventsHandler);
document.addEventListener("wheel", this._pointerEventsHandler);
}
visibilitychangeHandler() {
this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_VISIBILITYCHANGE, document.visibilityState);
}
resizeHandler() {
if (this._resizeTimeoutId)
Urso.clearTimeout(this._resizeTimeoutId);
this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_PRE_RESIZE);
this._resizeTimeoutId = Urso.setTimeout(
() => this.emit(Urso.events.EXTRA_BROWSEREVENTS_WINDOW_RESIZE),
this.RESIZE_DELAY
);
}
_pointerEventsHandler(event2) {
this.emit(Urso.events.EXTRA_BROWSEREVENTS_POINTER_EVENT, event2);
}
_keyPressHandler(event2) {
this.emit(Urso.events.EXTRA_BROWSEREVENTS_KEYPRESS_EVENT, event2);
}
}
var ExtensionType = /* @__PURE__ */ ((ExtensionType2) => {
ExtensionType2["Application"] = "application";
ExtensionType2["WebGLPipes"] = "webgl-pipes";
ExtensionType2["WebGLPipesAdaptor"] = "webgl-pipes-adaptor";
ExtensionType2["WebGLSystem"] = "webgl-system";
ExtensionType2["WebGPUPipes"] = "webgpu-pipes";
ExtensionType2["WebGPUPipesAdaptor"] = "webgpu-pipes-adaptor";
ExtensionType2["WebGPUSystem"] = "webgpu-system";
ExtensionType2["CanvasSystem"] = "canvas-system";
ExtensionType2["CanvasPipesAdaptor"] = "canvas-pipes-adaptor";
ExtensionType2["CanvasPipes"] = "canvas-pipes";
ExtensionType2["Asset"] = "asset";
ExtensionType2["LoadParser"] = "load-parser";
ExtensionType2["ResolveParser"] = "resolve-parser";
ExtensionType2["CacheParser"] = "cache-parser";
ExtensionType2["DetectionParser"] = "detection-parser";
ExtensionType2["MaskEffect"] = "mask-effect";
ExtensionType2["BlendMode"] = "blend-mode";
ExtensionType2["TextureSource"] = "texture-source";
ExtensionType2["Environment"] = "environment";
ExtensionType2["ShapeBuilder"] = "shape-builder";
ExtensionType2["Batcher"] = "batcher";
return ExtensionType2;
})(ExtensionType || {});
const normalizeExtension = (ext) => {
if (typeof ext === "function" || typeof ext === "object" && ext.extension) {
if (!ext.extension) {
throw new Error("Extension class must have an extension object");
}
const metadata = typeof ext.extension !== "object" ? { type: ext.extension } : ext.extension;
ext = { ...metadata, ref: ext };
}
if (typeof ext === "object") {
ext = { ...ext };
} else {
throw new Error("Invalid extension type");
}
if (typeof ext.type === "string") {
ext.type = [ext.type];
}
return ext;
};
const normalizeExtensionPriority = (ext, defaultPriority) => normalizeExtension(ext).priority ?? defaultPriority;
const extensions = {
/** @ignore */
_addHandlers: {},
/** @ignore */
_removeHandlers: {},
/** @ignore */
_queue: {},
/**
* Remove extensions from PixiJS.
* @param extensions - Extensions to be removed. Can be:
* - Extension class with static `extension` property
* - Extension format object with `type` and `ref`
* - Multiple extensions as separate arguments
* @returns {extensions} this for chaining
* @example
* ```ts
* // Remove a single extension
* extensions.remove(MyRendererPlugin);
*
* // Remove multiple extensions
* extensions.remove(
* MyRendererPlugin,
* MySystemPlugin
* );
* ```
* @see {@link ExtensionType} For available extension types
* @see {@link ExtensionFormat} For extension format details
*/
remove(...extensions2) {
extensions2.map(normalizeExtension).forEach((ext) => {
ext.type.forEach((type) => {
var _a2, _b;
return (_b = (_a2 = this._removeHandlers)[type]) == null ? void 0 : _b.call(_a2, ext);
});
});
return this;
},
/**
* Register new extensions with PixiJS. Extensions can be registered in multiple formats:
* - As a class with a static `extension` property
* - As an extension format object
* - As multiple extensions passed as separate arguments
* @param extensions - Extensions to add to PixiJS. Each can be:
* - A class with static `extension` property
* - An extension format object with `type` and `ref`
* - Multiple extensions as separate arguments
* @returns This extensions instance for chaining
* @example
* ```ts
* // Register a simple extension
* extensions.add(MyRendererPlugin);
*
* // Register multiple extensions
* extensions.add(
* MyRendererPlugin,
* MySystemPlugin,
* });
* ```
* @see {@link ExtensionType} For available extension types
* @see {@link ExtensionFormat} For extension format details
* @see {@link extensions.remove} For removing registered extensions
*/
add(...extensions2) {
extensions2.map(normalizeExtension).forEach((ext) => {
ext.type.forEach((type) => {
var _a2, _b;
const handlers = this._addHandlers;
const queue = this._queue;
if (!handlers[type]) {
queue[type] = queue[type] || [];
(_a2 = queue[type]) == null ? void 0 : _a2.push(ext);
} else {
(_b = handlers[type]) == null ? void 0 : _b.call(handlers, ext);
}
});
});
return this;
},
/**
* Internal method to handle extensions by name.
* @param type - The extension type.
* @param onAdd - Function handler when extensions are added/registered {@link StrictExtensionFormat}.
* @param onRemove - Function handler when extensions are removed/unregistered {@link StrictExtensionFormat}.
* @returns this for chaining.
* @internal
* @ignore
*/
handle(type, onAdd, onRemove) {
var _a2;
const addHandlers = this._addHandlers;
const removeHandlers = this._removeHandlers;
if (addHandlers[type] || removeHandlers[type]) {
throw new Error(`Extension type ${type} already has a handler`);
}
addHandlers[type] = onAdd;
removeHandlers[type] = onRemove;
const queue = this._queue;
if (queue[type]) {
(_a2 = queue[type]) == null ? void 0 : _a2.forEach((ext) => onAdd(ext));
delete queue[type];
}
return this;
},
/**
* Handle a type, but using a map by `name` property.
* @param type - Type of extension to handle.
* @param map - The object map of named extensions.
* @returns this for chaining.
* @ignore
*/
handleByMap(type, map) {
return this.handle(
type,
(extension) => {
if (extension.name) {
map[extension.name] = extension.ref;
}
},
(extension) => {
if (extension.name) {
delete map[extension.name];
}
}
);
},
/**
* Handle a type, but using a list of extensions with a `name` property.
* @param type - Type of extension to handle.
* @param map - The array of named extensions.
* @param defaultPriority - Fallback priority if none is defined.
* @returns this for chaining.
* @ignore
*/
handleByNamedList(type, map, defaultPriority = -1) {
return this.handle(
type,
(extension) => {
const index = map.findIndex((item) => item.name === extension.name);
if (index >= 0)
return;
map.push({ name: extension.name, value: extension.ref });
map.sort((a2, b2) => normalizeExtensionPriority(b2.value, defaultPriority) - normalizeExtensionPriority(a2.value, defaultPriority));
},
(extension) => {
const index = map.findIndex((item) => item.name === extension.name);
if (index !== -1) {
map.splice(index, 1);
}
}
);
},
/**
* Handle a type, but using a list of extensions.
* @param type - Type of extension to handle.
* @param list - The list of extensions.
* @param defaultPriority - The default priority to use if none is specified.
* @returns this for chaining.
* @ignore
*/
handleByList(type, list, defaultPriority = -1) {
return this.handle(
type,
(extension) => {
if (list.includes(extension.ref)) {
return;
}
list.push(extension.ref);
list.sort((a2, b2) => normalizeExtensionPriority(b2, defaultPriority) - normalizeExtensionPriority(a2, defaultPriority));
},
(extension) => {
const index = list.indexOf(extension.ref);
if (index !== -1) {
list.splice(index, 1);
}
}
);
},
/**
* Mixin the source object(s) properties into the target class's prototype.
* Copies all property descriptors from source objects to the target's prototype.
* @param Target - The target class to mix properties into
* @param sources - One or more source objects containing properties to mix in
* @example
* ```ts
* // Create a mixin with shared properties
* const moveable = {
* x: 0,
* y: 0,
* move(x: number, y: number) {
* this.x += x;
* this.y += y;
* }
* };
*
* // Create a mixin with computed properties
* const scalable = {
* scale: 1,
* get scaled() {
* return this.scale > 1;
* }
* };
*
* // Apply mixins to a class
* extensions.mixin(Sprite, moveable, scalable);
*
* // Use mixed-in properties
* const sprite = new Sprite();
* sprite.move(10, 20);
* console.log(sprite.x, sprite.y); // 10, 20
* ```
* @remarks
* - Copies all properties including getters/setters
* - Does not modify source objects
* - Preserves property descriptors
* @see {@link Object.defineProperties} For details on property descriptors
* @see {@link Object.getOwnPropertyDescriptors} For details on property copying
*/
mixin(Target, ...sources2) {
for (const source2 of sources2) {
Object.defineProperties(Target.prototype, Object.getOwnPropertyDescriptors(source2));
}
}
};
const browserExt = {
extension: {
type: ExtensionType.Environment,
name: "browser",
priority: -1
},
test: () => true,
load: async () => {
await Promise.resolve().then(() => browserAll);
}
};
const webworkerExt = {
extension: {
type: ExtensionType.Environment,
name: "webworker",
priority: 0
},
test: () => typeof self !== "undefined" && self.WorkerGlobalScope !== void 0,
load: async () => {
await Promise.resolve().then(() => webworkerAll);
}
};
class ObservablePoint {
/**
* Creates a new `ObservablePoint`
* @param observer - Observer to pass to listen for change events.
* @param {number} [x=0] - position of the point on the x axis
* @param {number} [y=0] - position of the point on the y axis
*/
constructor(observer, x2, y2) {
this._x = x2 || 0;
this._y = y2 || 0;
this._observer = observer;
}
/**
* Creates a clone of this point.
* @example
* ```ts
* // Basic cloning
* const point = new ObservablePoint(observer, 100, 200);
* const copy = point.clone();
*
* // Clone with new observer
* const newObserver = {
* _onUpdate: (p) => console.log(`Clone updated: (${p.x}, ${p.y})`)
* };
* const watched = point.clone(newObserver);
*
* // Verify independence
* watched.set(300, 400); // Only triggers new observer
* ```
* @param observer - Optional observer to pass to the new observable point
* @returns A copy of this observable point
* @see {@link ObservablePoint.copyFrom} For copying into existing point
* @see {@link Observer} For observer interface details
*/
clone(observer) {
return new ObservablePoint(observer ?? this._observer, this._x, this._y);
}
/**
* Sets the point to a new x and y position.
*
* If y is omitted, both x and y will be set to x.
* @example
* ```ts
* // Basic position setting
* const point = new ObservablePoint(observer);
* point.set(100, 200);
*
* // Set both x and y to same value
* point.set(50); // x=50, y=50
* ```
* @param x - Position on the x axis
* @param y - Position on the y axis, defaults to x
* @returns The point instance itself
* @see {@link ObservablePoint.copyFrom} For copying from another point
* @see {@link ObservablePoint.equals} For comparing positions
*/
set(x2 = 0, y2 = x2) {
if (this._x !== x2 || this._y !== y2) {
this._x = x2;
this._y = y2;
this._observer._onUpdate(this);
}
return this;
}
/**
* Copies x and y from the given point into this point.
* @example
* ```ts
* // Basic copying
* const source = new ObservablePoint(observer, 100, 200);
* const target = new ObservablePoint();
* target.copyFrom(source);
*
* // Copy and chain operations
* const point = new O