UNPKG

@urso/core

Version:
1,499 lines 2.95 MB
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