diff --git a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts index f35a7aea..fef802a7 100644 --- a/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts +++ b/front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts @@ -1,4 +1,3 @@ -import { MathUtils } from "../../../Utils/MathUtils"; import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../../Player/Animation"; export enum CustomWokaBodyPart { @@ -54,7 +53,7 @@ export class CustomWokaPreviewer extends Phaser.GameObjects.Container { [CustomWokaBodyPart.Hat]: this.scene.add.sprite(this.config.bodyPartsOffsetX, 0, "").setVisible(false), }; - this.background = this.scene.add.image(0, 0, "floorTexture"); + this.background = this.scene.add.image(0, 0, "floorTexture1"); this.frame = this.scene.add.graphics(); this.drawFrame(); this.setSize(this.SIZE, this.SIZE); diff --git a/front/src/Phaser/Components/CustomizeWoka/WokaBodyPartSlot.ts b/front/src/Phaser/Components/CustomizeWoka/WokaBodyPartSlot.ts index 9aee98f5..94e3bb33 100644 --- a/front/src/Phaser/Components/CustomizeWoka/WokaBodyPartSlot.ts +++ b/front/src/Phaser/Components/CustomizeWoka/WokaBodyPartSlot.ts @@ -1,5 +1,6 @@ import { GridItem } from "@home-based-studio/phaser3-utils"; import { GridItemEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/GridItem"; +import { CustomWokaBodyPart } from "./CustomWokaPreviewer"; export interface WokaBodyPartSlotConfig { color: number; @@ -8,9 +9,8 @@ export interface WokaBodyPartSlotConfig { borderSelectedColor: number; offsetX: number; offsetY: number; - bodyImageKey?: string; + textureKeys: Record; categoryImageKey?: string; - imageKey?: string; selected?: boolean; } @@ -22,8 +22,7 @@ export class WokaBodyPartSlot extends GridItem { private background: Phaser.GameObjects.Image; private frame: Phaser.GameObjects.Graphics; private categoryImage?: Phaser.GameObjects.Image; - private bodyImage: Phaser.GameObjects.Image; - private image: Phaser.GameObjects.Image; + private sprites: Record; private config: WokaBodyPartSlotConfig; @@ -36,12 +35,43 @@ export class WokaBodyPartSlot extends GridItem { this.config = config; + const textures = this.config.textureKeys; + this.sprites = { + [CustomWokaBodyPart.Accessory]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Accessory) + .setVisible(textures.Accessory !== ""), + [CustomWokaBodyPart.Body]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Body) + .setVisible(textures.Body !== ""), + [CustomWokaBodyPart.Clothes]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Clothes) + .setVisible(textures.Clothes !== ""), + [CustomWokaBodyPart.Eyes]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Eyes) + .setVisible(textures.Eyes !== ""), + [CustomWokaBodyPart.Hair]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Hair) + .setVisible(textures.Hair !== ""), + [CustomWokaBodyPart.Hat]: this.scene.add + .sprite(this.config.offsetX, this.config.offsetY, textures.Hat) + .setVisible(textures.Hat !== ""), + }; + this.selected = this.config.selected ?? false; - this.background = this.background = this.scene.add.image(0, 0, "floorTexture"); + this.background = this.background = this.scene.add.image(0, 0, `floorTexture1`); this.frame = this.scene.add.graphics(); this.drawFrame(); - this.add([this.background, this.frame]); + this.add([ + this.background, + this.frame, + this.sprites.Body, + this.sprites.Eyes, + this.sprites.Hair, + this.sprites.Clothes, + this.sprites.Hat, + this.sprites.Accessory, + ]); if (this.config.categoryImageKey) { this.categoryImage = this.scene.add @@ -52,18 +82,7 @@ export class WokaBodyPartSlot extends GridItem { this.add(this.categoryImage); } - this.bodyImage = this.scene.add - .image(this.config.offsetX, this.config.offsetY, this.config.bodyImageKey ?? "") - .setVisible(this.config.imageKey !== undefined); - - this.image = this.scene.add - .image(this.config.offsetX, this.config.offsetY, this.config.imageKey ?? "") - .setVisible(this.config.bodyImageKey !== undefined); - this.setSize(WokaBodyPartSlot.SIZE, WokaBodyPartSlot.SIZE); - - this.add([this.bodyImage, this.image]); - this.setInteractive({ cursor: "pointer" }); this.scene.input.setDraggable(this); @@ -72,29 +91,18 @@ export class WokaBodyPartSlot extends GridItem { this.scene.add.existing(this); } - public getContentData(): { bodyImageKey?: string; key?: string } { - return { bodyImageKey: this.config.bodyImageKey, key: this.config.imageKey }; + public getContentData(): Record { + return this.config.textureKeys; } - public setTextures(bodyTextureKey?: string, imageTextureKey?: string): void { - this.setBodyTexture(bodyTextureKey); - this.setImageTexture(imageTextureKey); - } - - public setBodyTexture(textureKey?: string, frame?: string | number): void { - this.bodyImage.setVisible(textureKey !== undefined && textureKey !== ""); - if (textureKey) { - this.bodyImage.setTexture(textureKey, frame); - this.config.bodyImageKey = textureKey; - } - } - - public setImageTexture(textureKey?: string, frame?: string | number): void { - this.image.setVisible(textureKey !== undefined && textureKey !== ""); - if (textureKey) { - this.image.setTexture(textureKey, frame); - this.config.imageKey = textureKey; - } + public setTextures(textureKeys: Record): void { + this.config.textureKeys = textureKeys; + this.sprites.Accessory.setTexture(textureKeys.Accessory).setVisible(textureKeys.Accessory !== ""); + this.sprites.Body.setTexture(textureKeys.Body).setVisible(textureKeys.Body !== ""); + this.sprites.Clothes.setTexture(textureKeys.Clothes).setVisible(textureKeys.Clothes !== ""); + this.sprites.Eyes.setTexture(textureKeys.Eyes).setVisible(textureKeys.Eyes !== ""); + this.sprites.Hair.setTexture(textureKeys.Hair).setVisible(textureKeys.Hair !== ""); + this.sprites.Hat.setTexture(textureKeys.Hat).setVisible(textureKeys.Hat !== ""); } public select(select: boolean = true): void { diff --git a/front/src/Phaser/Components/Ui/IconButton.ts b/front/src/Phaser/Components/Ui/IconButton.ts new file mode 100644 index 00000000..2fdc9cfd --- /dev/null +++ b/front/src/Phaser/Components/Ui/IconButton.ts @@ -0,0 +1,115 @@ +export interface IconButtonConfig { + width: number; + height: number; + iconTextureKey: string; + idle: IconButtonAppearanceConfig; + hover: IconButtonAppearanceConfig; + pressed: IconButtonAppearanceConfig; + selected: IconButtonAppearanceConfig; +} + +export interface IconButtonAppearanceConfig { + color: number; + borderThickness: number; + borderColor: number; +} + +export enum IconButtonEvent { + Clicked = "IconButton:Clicked", +} + +export class IconButton extends Phaser.GameObjects.Container { + private background: Phaser.GameObjects.Graphics; + private icon: Phaser.GameObjects.Image; + + private config: IconButtonConfig; + + private hovered: boolean = false; + private pressed: boolean = false; + private selected: boolean = false; + + constructor(scene: Phaser.Scene, x: number, y: number, config: IconButtonConfig) { + super(scene, x, y); + + this.config = config; + + this.background = this.scene.add.graphics(); + this.icon = this.scene.add.image(0, 0, this.config.iconTextureKey); + this.drawBackground(this.config.idle); + + this.add([this.background, this.icon]); + + this.setSize(this.config.width, this.config.height); + this.setInteractive({ cursor: "pointer" }); + + this.bindEventHandlers(); + + this.scene.add.existing(this); + } + + public select(select: boolean = true): void { + if (this.selected === select) { + return; + } + this.selected = select; + this.updateButtonAppearance(); + } + + private updateButtonAppearance(): void { + if (this.selected) { + this.drawBackground(this.config.selected); + return; + } + if (this.pressed) { + this.drawBackground(this.config.pressed); + return; + } + if (this.hovered) { + this.drawBackground(this.config.hover); + return; + } + this.drawBackground(this.config.idle); + } + + private drawBackground(appearance: IconButtonAppearanceConfig): void { + this.background.clear(); + this.background.fillStyle(appearance.color); + this.background.lineStyle(appearance.borderThickness, appearance.borderColor); + + const w = this.config.width; + const h = this.config.height; + + this.background.fillRect(-w / 2, -h / 2, w, h); + this.background.strokeRect(-w / 2, -h / 2, w, h); + } + + private bindEventHandlers(): void { + this.on(Phaser.Input.Events.POINTER_OVER, () => { + if (this.selected) { + return; + } + this.hovered = true; + this.updateButtonAppearance(); + }); + this.on(Phaser.Input.Events.POINTER_OUT, () => { + this.hovered = false; + this.pressed = false; + this.updateButtonAppearance(); + }); + this.on(Phaser.Input.Events.POINTER_DOWN, () => { + if (this.selected) { + return; + } + this.pressed = true; + this.updateButtonAppearance(); + }); + this.on(Phaser.Input.Events.POINTER_UP, () => { + if (this.selected) { + return; + } + this.pressed = false; + this.updateButtonAppearance(); + this.emit(IconButtonEvent.Clicked, this.selected); + }); + } +} diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index c8b89e11..4b4a97f9 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -27,6 +27,7 @@ import { DraggableGridEvent } from "@home-based-studio/phaser3-utils/lib/utils/g import { Button } from "../Components/Ui/Button"; import { wokaList } from "../../Messages/JsonMessages/PlayerTextures"; import { TexturesHelper } from "../Helpers/TexturesHelper"; +import { IconButton, IconButtonConfig, IconButtonEvent } from "../Components/Ui/IconButton"; export const CustomizeSceneName = "CustomizeScene"; @@ -35,7 +36,7 @@ export class CustomizeScene extends AbstractCharacterScene { private bodyPartsDraggableGridLeftShadow!: Phaser.GameObjects.Image; private bodyPartsDraggableGridRightShadow!: Phaser.GameObjects.Image; private bodyPartsDraggableGrid!: DraggableGrid; - private bodyPartsSlots!: Record; + private bodyPartsButtons!: Record; private randomizeButton!: Button; private finishButton!: Button; @@ -43,7 +44,6 @@ export class CustomizeScene extends AbstractCharacterScene { private selectedLayers: number[] = [0, 0, 0, 0, 0, 0]; private layers: BodyResourceDescriptionInterface[][] = []; private selectedBodyPartType?: CustomWokaBodyPart; - private selectedItemTextureKey?: string; protected lazyloadingAttempt = true; //permit to update texture loaded after renderer @@ -98,7 +98,10 @@ export class CustomizeScene extends AbstractCharacterScene { } public create(): void { - TexturesHelper.createFloorRectangleTexture(this, "floorTexture", 50, 50, "floorTiles", 0); + TexturesHelper.createFloorRectangleTexture(this, "floorTexture1", 50, 50, "floorTiles", 0); + TexturesHelper.createFloorRectangleTexture(this, "floorTexture2", 50, 50, "floorTiles", 1); + TexturesHelper.createFloorRectangleTexture(this, "floorTexture3", 50, 50, "floorTiles", 2); + TexturesHelper.createFloorRectangleTexture(this, "floorTexture4", 50, 50, "floorTiles", 3); this.customWokaPreviewer = new CustomWokaPreviewer( this, 0, @@ -126,7 +129,7 @@ export class CustomizeScene extends AbstractCharacterScene { this.bodyPartsDraggableGridLeftShadow = this.add .image(0, this.cameras.main.worldView.y + this.cameras.main.height, "gridEdgeShadow") .setAlpha(1, 0, 1, 0) - .setOrigin(0, 1); + .setOrigin(0, 0.5); this.bodyPartsDraggableGridRightShadow = this.add .image( @@ -136,38 +139,24 @@ export class CustomizeScene extends AbstractCharacterScene { ) .setAlpha(1, 0, 1, 0) .setFlipX(true) - .setOrigin(1, 1); + .setOrigin(1, 0.5); - this.bodyPartsSlots = { - [CustomWokaBodyPart.Hair]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconHair", - }), - [CustomWokaBodyPart.Body]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconBody", - }), - [CustomWokaBodyPart.Accessory]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconAccessory", - }), - [CustomWokaBodyPart.Hat]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconHat", - }), - [CustomWokaBodyPart.Clothes]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconClothes", - }), - [CustomWokaBodyPart.Eyes]: new WokaBodyPartSlot(this, 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), - categoryImageKey: "iconEyes", - }), + this.bodyPartsButtons = { + [CustomWokaBodyPart.Accessory]: new IconButton( + this, + 0, + 0, + this.getDefaultIconButtonConfig("iconAccessory") + ), + [CustomWokaBodyPart.Body]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconBody")), + [CustomWokaBodyPart.Clothes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconClothes")), + [CustomWokaBodyPart.Eyes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconEyes")), + [CustomWokaBodyPart.Hair]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHair")), + [CustomWokaBodyPart.Hat]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHat")), }; this.selectedBodyPartType = CustomWokaBodyPart.Body; - this.selectedItemTextureKey = this.layers[CustomWokaBodyPartOrder.Body][0].id; - this.bodyPartsSlots.Body.select(); + this.bodyPartsButtons.Body.select(); this.initializeRandomizeButton(); this.initializeFinishButton(); @@ -185,10 +174,10 @@ export class CustomizeScene extends AbstractCharacterScene { public onResize(): void { this.handleCustomWokaPreviewerOnResize(); - this.handleBodyPartSlotsOnResize(); - this.handleBodyPartsDraggableGridOnResize(); + this.handleBodyPartButtonsOnResize(); this.handleRandomizeButtonOnResize(); this.handleFinishButtonOnResize(); + this.handleBodyPartsDraggableGridOnResize(); } public nextSceneToCamera() { @@ -218,6 +207,34 @@ export class CustomizeScene extends AbstractCharacterScene { this.scene.run(SelectCharacterSceneName); } + private getDefaultIconButtonConfig(iconTextureKey: string): IconButtonConfig { + return { + iconTextureKey, + width: 25, + height: 25, + idle: { + color: 0xffffff, + borderThickness: 3, + borderColor: 0xe7e7e7, + }, + hover: { + color: 0xe7e7e7, + borderThickness: 3, + borderColor: 0xadafbc, + }, + pressed: { + color: 0xadafbc, + borderThickness: 3, + borderColor: 0xadafbc, + }, + selected: { + color: 0xadafbc, + borderThickness: 3, + borderColor: 0x209cee, + }, + }; + } + private initializeRandomizeButton(): void { this.randomizeButton = new Button(this, 50, 50, { width: 95, @@ -275,80 +292,101 @@ export class CustomizeScene extends AbstractCharacterScene { for (const layerItem of this.selectedLayers) { const bodyPart = CustomWokaBodyPart[CustomWokaBodyPartOrder[i] as CustomWokaBodyPart]; this.customWokaPreviewer.updateSprite(this.layers[i][layerItem].id, bodyPart); - this.bodyPartsSlots[bodyPart].setTextures( - this.layers[CustomWokaBodyPartOrder.Body][this.selectedLayers[CustomWokaBodyPartOrder.Body]].id, - this.layers[i][layerItem].id - ); i += 1; } } + private getCurrentlySelectedWokaTexturesRecord(): Record { + return { + [CustomWokaBodyPart.Accessory]: + this.layers[CustomWokaBodyPartOrder.Accessory][this.selectedLayers[CustomWokaBodyPartOrder.Accessory]] + .id, + [CustomWokaBodyPart.Body]: + this.layers[CustomWokaBodyPartOrder.Body][this.selectedLayers[CustomWokaBodyPartOrder.Body]].id, + [CustomWokaBodyPart.Clothes]: + this.layers[CustomWokaBodyPartOrder.Clothes][this.selectedLayers[CustomWokaBodyPartOrder.Clothes]].id, + [CustomWokaBodyPart.Eyes]: + this.layers[CustomWokaBodyPartOrder.Eyes][this.selectedLayers[CustomWokaBodyPartOrder.Eyes]].id, + [CustomWokaBodyPart.Hair]: + this.layers[CustomWokaBodyPartOrder.Hair][this.selectedLayers[CustomWokaBodyPartOrder.Hair]].id, + [CustomWokaBodyPart.Hat]: + this.layers[CustomWokaBodyPartOrder.Hat][this.selectedLayers[CustomWokaBodyPartOrder.Hat]].id, + }; + } + private handleCustomWokaPreviewerOnResize(): void { this.customWokaPreviewer.x = this.cameras.main.worldView.x + this.cameras.main.width / 2; this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + 10; } - private handleBodyPartSlotsOnResize(): void { + private handleBodyPartButtonsOnResize(): void { const ratio = innerHeight / innerWidth; - const slotDimension = 100; + const slotDimension = 50; - for (const part in this.bodyPartsSlots) { - this.bodyPartsSlots[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension); + for (const part in this.bodyPartsButtons) { + this.bodyPartsButtons[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension); } - const slotSize = this.bodyPartsSlots.Accessory.displayHeight; + const slotSize = this.bodyPartsButtons.Accessory.displayHeight; if (ratio > 1.6) { const middle = Math.floor(this.customWokaPreviewer.x); - const left = Math.floor(middle - slotSize - 10); - const right = Math.floor(middle + slotSize + 10); + const left = Math.floor(middle - slotSize - 23); + const right = Math.floor(middle + slotSize + 23); const top = Math.floor( - this.customWokaPreviewer.y + this.customWokaPreviewer.displayHeight * 0.5 + slotSize * 1.5 + 9 + this.customWokaPreviewer.y + this.customWokaPreviewer.displayHeight * 0.5 + slotSize * 1.5 + 30 ); - const bottom = Math.floor(top + slotSize + 10); + const bottom = Math.floor(top + slotSize + 23); - this.bodyPartsSlots.Body.setPosition(left, top); - this.bodyPartsSlots.Eyes.setPosition(middle, top); - this.bodyPartsSlots.Hair.setPosition(right, top); - this.bodyPartsSlots.Clothes.setPosition(left, bottom); - this.bodyPartsSlots.Hat.setPosition(middle, bottom); - this.bodyPartsSlots.Accessory.setPosition(right, bottom); + this.bodyPartsButtons.Body.setPosition(left, top); + this.bodyPartsButtons.Eyes.setPosition(middle, top); + this.bodyPartsButtons.Hair.setPosition(right, top); + this.bodyPartsButtons.Clothes.setPosition(left, bottom); + this.bodyPartsButtons.Hat.setPosition(middle, bottom); + this.bodyPartsButtons.Accessory.setPosition(right, bottom); return; } const left = Math.floor( - this.customWokaPreviewer.x - this.customWokaPreviewer.displayWidth * 0.5 - slotSize * 0.5 - 10 + this.customWokaPreviewer.x - this.customWokaPreviewer.displayWidth * 0.5 - slotSize * 0.5 - 24 ); - const leftEdge = Math.floor(left - slotSize - 10); const right = Math.floor( - this.customWokaPreviewer.x + this.customWokaPreviewer.displayWidth * 0.5 + slotSize * 0.5 + 10 + this.customWokaPreviewer.x + this.customWokaPreviewer.displayWidth * 0.5 + slotSize * 0.5 + 24 ); - const rightEdge = Math.floor(right + slotSize + 10); - const top = Math.floor(0 + slotSize * 0.5 + 9); - const middle = Math.floor(top + slotSize + 10); - const bottom = Math.floor(middle + slotSize + 10); + const top = Math.floor(0 + slotSize * 0.5 + 11); + const middle = Math.floor(top + slotSize + 24); + const bottom = Math.floor(middle + slotSize + 24); - this.bodyPartsSlots.Body.setPosition(left, top); - this.bodyPartsSlots.Eyes.setPosition(left, middle); - this.bodyPartsSlots.Hair.setPosition(ratio < 0.6 ? leftEdge : left, ratio < 0.6 ? middle : bottom); - this.bodyPartsSlots.Clothes.setPosition(right, top); - this.bodyPartsSlots.Hat.setPosition(right, middle); - this.bodyPartsSlots.Accessory.setPosition(ratio < 0.6 ? rightEdge : right, ratio < 0.6 ? middle : bottom); + this.bodyPartsButtons.Body.setPosition(left, top); + this.bodyPartsButtons.Eyes.setPosition(left, middle); + this.bodyPartsButtons.Hair.setPosition(left, bottom); + this.bodyPartsButtons.Clothes.setPosition(right, top); + this.bodyPartsButtons.Hat.setPosition(right, middle); + this.bodyPartsButtons.Accessory.setPosition(right, bottom); } private handleBodyPartsDraggableGridOnResize(): void { const gridHeight = 110; const gridWidth = innerWidth / waScaleManager.getActualZoom(); + + const gridTopMargin = Math.max( + this.finishButton.y + this.finishButton.displayHeight * 0.5, + this.bodyPartsButtons.Hair.y + this.bodyPartsButtons.Hair.displayHeight * 0.5 + ); + const gridBottomMargin = this.cameras.main.worldView.y + this.cameras.main.height; + + const yPos = gridTopMargin + (gridBottomMargin - gridTopMargin) * 0.5; + const gridPos = { x: this.cameras.main.worldView.x + this.cameras.main.width / 2, - y: this.cameras.main.worldView.y + this.cameras.main.height - gridHeight * 0.5 - 5, + y: yPos, }; - this.bodyPartsDraggableGridLeftShadow.setPosition(0, this.cameras.main.worldView.y + this.cameras.main.height); + this.bodyPartsDraggableGridLeftShadow.setPosition(0, yPos); this.bodyPartsDraggableGridRightShadow.setPosition( this.cameras.main.worldView.x + this.cameras.main.width, - this.cameras.main.worldView.y + this.cameras.main.height + yPos ); try { @@ -399,34 +437,33 @@ export class CustomizeScene extends AbstractCharacterScene { }; } - private getDefaultWokaBodyPartSlotConfig(): WokaBodyPartSlotConfig { + private getWokaBodyPartSlotConfig(bodyPart?: CustomWokaBodyPart, newTextureKey?: string): WokaBodyPartSlotConfig { + const textures = this.getCurrentlySelectedWokaTexturesRecord(); + if (bodyPart && newTextureKey) { + textures[bodyPart] = newTextureKey; + } return { color: 0xffffff, borderThickness: 1, borderColor: 0xadafbc, borderSelectedColor: 0x209cee, + textureKeys: textures, offsetX: -4, offsetY: 2, }; } private bindEventHandlers(): void { + this.bindKeyboardEventHandlers(); this.events.addListener("wake", () => { waScaleManager.saveZoom(); waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1; }); - this.input.keyboard.on("keyup-ENTER", () => { - this.nextSceneToCamera(); - }); - this.input.keyboard.on("keyup-BACKSPACE", () => { - this.backToPreviousScene(); - }); - this.randomizeButton.on(Phaser.Input.Events.POINTER_UP, () => { this.randomizeOutfit(); this.clearGrid(); - this.deselectAllSlots(); + this.deselectAllButtons(); this.refreshPlayerCurrentOutfit(); }); @@ -435,52 +472,136 @@ export class CustomizeScene extends AbstractCharacterScene { }); for (const bodyPart in CustomWokaBodyPart) { - const slot = this.bodyPartsSlots[bodyPart as CustomWokaBodyPart]; - slot.on(WokaBodyPartSlotEvent.Clicked, (selected: boolean) => { + const button = this.bodyPartsButtons[bodyPart as CustomWokaBodyPart]; + button.on(IconButtonEvent.Clicked, (selected: boolean) => { if (!selected) { - this.selectedBodyPartType = bodyPart as CustomWokaBodyPart; - this.selectedItemTextureKey = slot.getContentData().key ?? slot.getContentData().bodyImageKey; - this.deselectAllSlots(); - slot.select(true); - this.populateGrid(); - if (!this.selectedItemTextureKey) { - return; - } - const selectedGridItem = this.selectGridItem(); - if (!selectedGridItem) { - return; - } - this.bodyPartsDraggableGrid.moveContentToBeginning(); - this.centerGridOnItem(selectedGridItem); - } else { - this.selectedBodyPartType = undefined; - slot.select(false); - this.clearGrid(); + this.selectBodyPartType(bodyPart as CustomWokaBodyPart); } }); } this.bodyPartsDraggableGrid.on(DraggableGridEvent.ItemClicked, (item: WokaBodyPartSlot) => { void this.bodyPartsDraggableGrid.centerOnItem(this.bodyPartsDraggableGrid.getAllItems().indexOf(item), 500); - this.bodyPartsDraggableGrid.getAllItems().forEach((slot) => (slot as WokaBodyPartSlot).select(false)); - this.changeOutfitPart(Number(item.getId())); - this.refreshPlayerCurrentOutfit(); + this.deselectAllSlots(); item.select(true); + this.setNewBodyPart(Number(item.getId())); }); } - private selectGridItem(): WokaBodyPartSlot | undefined { - const items = this.bodyPartsDraggableGrid.getAllItems() as WokaBodyPartSlot[]; - let item: WokaBodyPartSlot | undefined; - if (this.selectedBodyPartType === CustomWokaBodyPart.Body) { - item = items.find((item) => item.getContentData().bodyImageKey === this.selectedItemTextureKey); - } else { - item = items.find((item) => item.getContentData().key === this.selectedItemTextureKey); + private selectBodyPartType(bodyPart: CustomWokaBodyPart): void { + this.selectedBodyPartType = bodyPart; + this.deselectAllButtons(); + const button = this.bodyPartsButtons[bodyPart]; + button.select(true); + this.populateGrid(); + const selectedGridItem = this.selectGridItem(); + if (!selectedGridItem) { + return; } + this.bodyPartsDraggableGrid.moveContentToBeginning(); + this.centerGridOnItem(selectedGridItem); + } + + private bindKeyboardEventHandlers(): void { + this.input.keyboard.on("keyup-ENTER", () => { + this.nextSceneToCamera(); + }); + this.input.keyboard.on("keyup-BACKSPACE", () => { + this.backToPreviousScene(); + }); + this.input.keyboard.on("keydown-LEFT", () => { + this.selectNextGridItem(true); + }); + this.input.keyboard.on("keydown-RIGHT", () => { + this.selectNextGridItem(); + }); + this.input.keyboard.on("keydown-UP", () => { + this.selectNextCategory(true); + }); + this.input.keyboard.on("keydown-DOWN", () => { + this.selectNextCategory(); + }); + this.input.keyboard.on("keydown-W", () => { + this.selectNextCategory(true); + }); + this.input.keyboard.on("keydown-S", () => { + this.selectNextCategory(); + }); + this.input.keyboard.on("keydown-A", () => { + this.selectNextGridItem(true); + }); + this.input.keyboard.on("keydown-D", () => { + this.selectNextGridItem(); + }); + } + + private setNewBodyPart(bodyPartIndex: number) { + this.changeOutfitPart(bodyPartIndex); + this.refreshPlayerCurrentOutfit(); + } + + private selectGridItem(): WokaBodyPartSlot | undefined { + const bodyPartType = this.selectedBodyPartType; + if (!bodyPartType) { + return; + } + const items = this.bodyPartsDraggableGrid.getAllItems() as WokaBodyPartSlot[]; + const item = items.find( + (item) => item.getContentData()[bodyPartType] === this.getBodyPartSelectedItemId(bodyPartType) + ); item?.select(); return item; } + private getBodyPartSelectedItemId(bodyPartType: CustomWokaBodyPart): string { + const categoryIndex = CustomWokaBodyPartOrder[bodyPartType]; + return this.layers[categoryIndex][this.selectedLayers[categoryIndex]].id; + } + + private selectNextGridItem(previous: boolean = false): void { + if (!this.selectedBodyPartType) { + return; + } + const currentIndex = this.getCurrentlySelectedItemIndex(); + if (previous ? currentIndex > 0 : currentIndex < this.bodyPartsDraggableGrid.getAllItems().length - 1) { + this.deselectAllSlots(); + const item = this.bodyPartsDraggableGrid.getAllItems()[ + currentIndex + (previous ? -1 : 1) + ] as WokaBodyPartSlot; + if (item) { + item.select(); + this.setNewBodyPart(Number(item.getId())); + this.centerGridOnItem(item); + } + } + } + + private selectNextCategory(previous: boolean = false): void { + if (!this.selectedBodyPartType) { + this.selectBodyPartType(CustomWokaBodyPart.Body); + return; + } + if (previous && this.selectedBodyPartType === CustomWokaBodyPart.Body) { + return; + } + if (!previous && this.selectedBodyPartType === CustomWokaBodyPart.Accessory) { + return; + } + const index = CustomWokaBodyPartOrder[this.selectedBodyPartType] + (previous ? -1 : 1); + this.selectBodyPartType(CustomWokaBodyPart[CustomWokaBodyPartOrder[index] as CustomWokaBodyPart]); + } + + private getCurrentlySelectedItemIndex(): number { + const bodyPartType = this.selectedBodyPartType; + if (!bodyPartType) { + return -1; + } + const items = this.bodyPartsDraggableGrid.getAllItems() as WokaBodyPartSlot[]; + return items.findIndex( + (item) => item.getContentData()[bodyPartType] === this.getBodyPartSelectedItemId(bodyPartType) + ); + } + private centerGridOnItem(item: WokaBodyPartSlot, duration: number = 500): void { void this.bodyPartsDraggableGrid.centerOnItem( this.bodyPartsDraggableGrid.getAllItems().indexOf(item), @@ -515,21 +636,12 @@ export class CustomizeScene extends AbstractCharacterScene { 0, 0, { - ...this.getDefaultWokaBodyPartSlotConfig(), + ...this.getWokaBodyPartSlotConfig(this.selectedBodyPartType, bodyPartsLayer[i].id), offsetX: 0, offsetY: 0, }, i ).setDisplaySize(this.SLOT_DIMENSION, this.SLOT_DIMENSION); - if (this.selectedBodyPartType === CustomWokaBodyPart.Body) { - slot.setBodyTexture(bodyPartsLayer[i].id); - slot.setImageTexture(); - } else { - slot.setBodyTexture( - this.layers[CustomWokaBodyPartOrder.Body][this.selectedLayers[CustomWokaBodyPartOrder.Body]].id - ); - slot.setImageTexture(bodyPartsLayer[i].id); - } this.bodyPartsDraggableGrid.addItem(slot); } } @@ -538,9 +650,13 @@ export class CustomizeScene extends AbstractCharacterScene { this.bodyPartsDraggableGrid.clearAllItems(); } - private deselectAllSlots(): void { + private deselectAllButtons(): void { for (const bodyPart in CustomWokaBodyPart) { - this.bodyPartsSlots[bodyPart as CustomWokaBodyPart].select(false); + this.bodyPartsButtons[bodyPart as CustomWokaBodyPart].select(false); } } + + private deselectAllSlots(): void { + this.bodyPartsDraggableGrid.getAllItems().forEach((slot) => (slot as WokaBodyPartSlot).select(false)); + } } diff --git a/front/src/WebRtc/VideoPeer.ts b/front/src/WebRtc/VideoPeer.ts index 50c3e19f..97f855b7 100644 --- a/front/src/WebRtc/VideoPeer.ts +++ b/front/src/WebRtc/VideoPeer.ts @@ -10,8 +10,6 @@ import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore"; import { getIceServersConfig } from "../Components/Video/utils"; import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils"; import { SoundMeter } from "../Phaser/Components/SoundMeter"; -import { AudioContext } from "standardized-audio-context"; -import { Console } from "console"; import Peer from "simple-peer/simplepeer.min.js"; import { Buffer } from "buffer";