import { EnableCameraSceneName } from "./EnableCameraScene"; import Rectangle = Phaser.GameObjects.Rectangle; import { loadAllLayers } from "../Entity/PlayerTexturesLoadingManager"; import Sprite = Phaser.GameObjects.Sprite; import { gameManager } from "../Game/GameManager"; import { localUserStore } from "../../Connexion/LocalUserStore"; import { Loader } from "../Components/Loader"; import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures"; import { AbstractCharacterScene } from "./AbstractCharacterScene"; import { areCharacterLayersValid } from "../../Connexion/LocalUser"; import { SelectCharacterSceneName } from "./SelectCharacterScene"; import { activeRowStore, customCharacterSceneVisibleStore } from "../../Stores/CustomCharacterStore"; import { waScaleManager } from "../Services/WaScaleManager"; import { isMobile } from "../../Enum/EnvironmentVariable"; import { CustomizedCharacter } from "../Entity/CustomizedCharacter"; import { get } from "svelte/store"; import { analyticsClient } from "../../Administration/AnalyticsClient"; export const CustomizeSceneName = "CustomizeScene"; export class CustomizeScene extends AbstractCharacterScene { private Rectangle!: Rectangle; private selectedLayers: number[] = [0]; private containersRow: CustomizedCharacter[][] = []; private layers: BodyResourceDescriptionInterface[][] = []; protected lazyloadingAttempt = true; //permit to update texture loaded after renderer private moveHorizontally: number = 0; private moveVertically: number = 0; private loader: Loader; constructor() { super({ key: CustomizeSceneName, }); this.loader = new Loader(this); } preload() { this.loadCustomSceneSelectCharacters() .then((bodyResourceDescriptions) => { bodyResourceDescriptions.forEach((bodyResourceDescription) => { if ( bodyResourceDescription.level == undefined || bodyResourceDescription.level < 0 || bodyResourceDescription.level > 5 ) { throw new Error("Texture level is null"); } this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription); }); this.lazyloadingAttempt = true; }) .catch((e) => console.error(e)); this.layers = loadAllLayers(this.load); this.lazyloadingAttempt = false; //this function must stay at the end of preload function this.loader.addLoader(); } create() { customCharacterSceneVisibleStore.set(true); this.events.addListener("wake", () => { waScaleManager.saveZoom(); waScaleManager.zoomModifier = isMobile() ? 3 : 1; customCharacterSceneVisibleStore.set(true); }); waScaleManager.saveZoom(); waScaleManager.zoomModifier = isMobile() ? 3 : 1; this.Rectangle = this.add.rectangle( this.cameras.main.worldView.x + this.cameras.main.width / 2, this.cameras.main.worldView.y + this.cameras.main.height / 3, 32, 33 ); this.Rectangle.setStrokeStyle(2, 0xffffff); this.add.existing(this.Rectangle); this.createCustomizeLayer(0, 0, 0); this.createCustomizeLayer(0, 0, 1); this.createCustomizeLayer(0, 0, 2); this.createCustomizeLayer(0, 0, 3); this.createCustomizeLayer(0, 0, 4); this.createCustomizeLayer(0, 0, 5); this.moveLayers(); this.input.keyboard.on("keyup-ENTER", () => { this.nextSceneToCamera(); }); this.input.keyboard.on("keyup-BACKSPACE", () => { this.backToPreviousScene(); }); // Note: the key bindings are not directly put on the moveCursorVertically or moveCursorHorizontally methods // because if 2 such events are fired close to one another, it makes the whole application crawl to a halt (for a reason I cannot // explain, the list of sprites managed by the update list become immense this.input.keyboard.on("keyup-RIGHT", () => (this.moveHorizontally = 1)); this.input.keyboard.on("keyup-LEFT", () => (this.moveHorizontally = -1)); this.input.keyboard.on("keyup-DOWN", () => (this.moveVertically = 1)); this.input.keyboard.on("keyup-UP", () => (this.moveVertically = -1)); const customCursorPosition = localUserStore.getCustomCursorPosition(); if (customCursorPosition) { activeRowStore.set(customCursorPosition.activeRow); this.selectedLayers = customCursorPosition.selectedLayers; this.moveLayers(); this.updateSelectedLayer(); } this.onResize(); } public moveCursorHorizontally(index: number): void { this.moveHorizontally = index; } public moveCursorVertically(index: number): void { this.moveVertically = index; } private doMoveCursorHorizontally(index: number): void { this.selectedLayers[get(activeRowStore)] += index; if (this.selectedLayers[get(activeRowStore)] < 0) { this.selectedLayers[get(activeRowStore)] = 0; } else if (this.selectedLayers[get(activeRowStore)] > this.layers[get(activeRowStore)].length - 1) { this.selectedLayers[get(activeRowStore)] = this.layers[get(activeRowStore)].length - 1; } this.moveLayers(); this.updateSelectedLayer(); this.saveInLocalStorage(); } private doMoveCursorVertically(index: number): void { activeRowStore.set(get(activeRowStore) + index); if (get(activeRowStore) < 0) { activeRowStore.set(0); } else if (get(activeRowStore) > this.layers.length - 1) { activeRowStore.set(this.layers.length - 1); } this.moveLayers(); this.saveInLocalStorage(); } private saveInLocalStorage() { localUserStore.setCustomCursorPosition(get(activeRowStore), this.selectedLayers); } /** * @param x, the layer's vertical position * @param y, the layer's horizontal position * @param layerNumber, index of the this.layers array * create the layer and display it on the scene */ private createCustomizeLayer(x: number, y: number, layerNumber: number): void { this.containersRow[layerNumber] = []; this.selectedLayers[layerNumber] = 0; let alpha = 0; let layerPosX = 0; for (let i = 0; i < this.layers[layerNumber].length; i++) { const container = this.generateCharacter(300 + x + layerPosX, y, layerNumber, i); this.containersRow[layerNumber][i] = container; this.add.existing(container); layerPosX += 30; alpha += 0.1; } } /** * Generates a character from the current selected items BUT replaces * one layer item with an item we pass in parameter. * * Current selected items are fetched from this.selectedLayers * * @param x, * @param y, * @param layerNumber, The selected layer number (0 for body...) * @param selectedItem, The number of the item select (0 for black body...) */ private generateCharacter(x: number, y: number, layerNumber: number, selectedItem: number) { return new CustomizedCharacter(this, x, y, this.getContainerChildren(layerNumber, selectedItem)); } private getContainerChildren(layerNumber: number, selectedItem: number): Array { const children: Array = new Array(); for (let j = 0; j <= layerNumber; j++) { if (j === layerNumber) { children.push(this.layers[j][selectedItem].name); } else { const layer = this.selectedLayers[j]; if (layer === undefined) { continue; } children.push(this.layers[j][layer].name); } } return children; } /** * Move the layer left, right, up and down and update the selected layer */ private moveLayers(): void { const screenCenterX = this.cameras.main.worldView.x + this.cameras.main.width / 2; const screenCenterY = this.cameras.main.worldView.y + this.cameras.main.height / 3; const screenWidth = this.game.renderer.width; const screenHeight = this.game.renderer.height; for (let i = 0; i < this.containersRow.length; i++) { for (let j = 0; j < this.containersRow[i].length; j++) { let selectedX = this.selectedLayers[i]; if (selectedX === undefined) { selectedX = 0; } this.containersRow[i][j].x = screenCenterX + (j - selectedX) * 40; this.containersRow[i][j].y = screenCenterY + (i - get(activeRowStore)) * 40; const alpha1 = (Math.abs(selectedX - j) * 47 * 2) / screenWidth; const alpha2 = (Math.abs(get(activeRowStore) - i) * 49 * 2) / screenHeight; this.containersRow[i][j].setAlpha((1 - alpha1) * (1 - alpha2)); } } } /** * @param x, the sprite's vertical position * @param y, the sprites's horizontal position * @param name, the sprite's name * @return a new sprite */ private generateLayers(x: number, y: number, name: string): Sprite { //return new Sprite(this, x, y, name); return this.add.sprite(0, 0, name); } private updateSelectedLayer() { for (let i = 0; i < this.containersRow.length; i++) { for (let j = 0; j < this.containersRow[i].length; j++) { const children = this.getContainerChildren(i, j); this.containersRow[i][j].updateSprites(children); } } } update(time: number, delta: number): void { if (this.lazyloadingAttempt) { this.moveLayers(); this.doMoveCursorHorizontally(this.moveHorizontally); this.lazyloadingAttempt = false; } if (this.moveHorizontally !== 0) { this.doMoveCursorHorizontally(this.moveHorizontally); this.moveHorizontally = 0; } if (this.moveVertically !== 0) { this.doMoveCursorVertically(this.moveVertically); this.moveVertically = 0; } } public onResize(): void { this.moveLayers(); this.Rectangle.x = this.cameras.main.worldView.x + this.cameras.main.width / 2; this.Rectangle.y = this.cameras.main.worldView.y + this.cameras.main.height / 3; } public nextSceneToCamera() { const layers: string[] = []; let i = 0; for (const layerItem of this.selectedLayers) { if (layerItem !== undefined) { layers.push(this.layers[i][layerItem].name); } i++; } if (!areCharacterLayersValid(layers)) { return; } analyticsClient.validationWoka("CustomizeWoka"); gameManager.setCharacterLayers(layers); this.scene.sleep(CustomizeSceneName); waScaleManager.restoreZoom(); this.events.removeListener("wake"); gameManager.tryResumingGame(EnableCameraSceneName); customCharacterSceneVisibleStore.set(false); } public backToPreviousScene() { this.scene.sleep(CustomizeSceneName); waScaleManager.restoreZoom(); this.scene.run(SelectCharacterSceneName); customCharacterSceneVisibleStore.set(false); } }