New custom woka scene full clothes (#2023)

* center grid if possible

* whole outfit for every slot

* switched bodyPart slots into buttons

* change categories and body parts with WSAD / arrow keys

Co-authored-by: Piotr 'pwh' Hanusiak <p.hanusiak@workadventu.re>
This commit is contained in:
Piotr Hanusiak 2022-04-04 13:01:21 +02:00 committed by GitHub
parent d0ad5f8299
commit 32b777b5cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 398 additions and 162 deletions

View File

@ -1,4 +1,3 @@
import { MathUtils } from "../../../Utils/MathUtils";
import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../../Player/Animation"; import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../../Player/Animation";
export enum CustomWokaBodyPart { 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), [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.frame = this.scene.add.graphics();
this.drawFrame(); this.drawFrame();
this.setSize(this.SIZE, this.SIZE); this.setSize(this.SIZE, this.SIZE);

View File

@ -1,5 +1,6 @@
import { GridItem } from "@home-based-studio/phaser3-utils"; import { GridItem } from "@home-based-studio/phaser3-utils";
import { GridItemEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/GridItem"; import { GridItemEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/GridItem";
import { CustomWokaBodyPart } from "./CustomWokaPreviewer";
export interface WokaBodyPartSlotConfig { export interface WokaBodyPartSlotConfig {
color: number; color: number;
@ -8,9 +9,8 @@ export interface WokaBodyPartSlotConfig {
borderSelectedColor: number; borderSelectedColor: number;
offsetX: number; offsetX: number;
offsetY: number; offsetY: number;
bodyImageKey?: string; textureKeys: Record<CustomWokaBodyPart, string>;
categoryImageKey?: string; categoryImageKey?: string;
imageKey?: string;
selected?: boolean; selected?: boolean;
} }
@ -22,8 +22,7 @@ export class WokaBodyPartSlot extends GridItem {
private background: Phaser.GameObjects.Image; private background: Phaser.GameObjects.Image;
private frame: Phaser.GameObjects.Graphics; private frame: Phaser.GameObjects.Graphics;
private categoryImage?: Phaser.GameObjects.Image; private categoryImage?: Phaser.GameObjects.Image;
private bodyImage: Phaser.GameObjects.Image; private sprites: Record<CustomWokaBodyPart, Phaser.GameObjects.Sprite>;
private image: Phaser.GameObjects.Image;
private config: WokaBodyPartSlotConfig; private config: WokaBodyPartSlotConfig;
@ -36,12 +35,43 @@ export class WokaBodyPartSlot extends GridItem {
this.config = config; 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.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.frame = this.scene.add.graphics();
this.drawFrame(); 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) { if (this.config.categoryImageKey) {
this.categoryImage = this.scene.add this.categoryImage = this.scene.add
@ -52,18 +82,7 @@ export class WokaBodyPartSlot extends GridItem {
this.add(this.categoryImage); 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.setSize(WokaBodyPartSlot.SIZE, WokaBodyPartSlot.SIZE);
this.add([this.bodyImage, this.image]);
this.setInteractive({ cursor: "pointer" }); this.setInteractive({ cursor: "pointer" });
this.scene.input.setDraggable(this); this.scene.input.setDraggable(this);
@ -72,29 +91,18 @@ export class WokaBodyPartSlot extends GridItem {
this.scene.add.existing(this); this.scene.add.existing(this);
} }
public getContentData(): { bodyImageKey?: string; key?: string } { public getContentData(): Record<CustomWokaBodyPart, string> {
return { bodyImageKey: this.config.bodyImageKey, key: this.config.imageKey }; return this.config.textureKeys;
} }
public setTextures(bodyTextureKey?: string, imageTextureKey?: string): void { public setTextures(textureKeys: Record<CustomWokaBodyPart, string>): void {
this.setBodyTexture(bodyTextureKey); this.config.textureKeys = textureKeys;
this.setImageTexture(imageTextureKey); 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 !== "");
public setBodyTexture(textureKey?: string, frame?: string | number): void { this.sprites.Eyes.setTexture(textureKeys.Eyes).setVisible(textureKeys.Eyes !== "");
this.bodyImage.setVisible(textureKey !== undefined && textureKey !== ""); this.sprites.Hair.setTexture(textureKeys.Hair).setVisible(textureKeys.Hair !== "");
if (textureKey) { this.sprites.Hat.setTexture(textureKeys.Hat).setVisible(textureKeys.Hat !== "");
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 select(select: boolean = true): void { public select(select: boolean = true): void {

View File

@ -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);
});
}
}

View File

@ -27,6 +27,7 @@ import { DraggableGridEvent } from "@home-based-studio/phaser3-utils/lib/utils/g
import { Button } from "../Components/Ui/Button"; import { Button } from "../Components/Ui/Button";
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures"; import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
import { TexturesHelper } from "../Helpers/TexturesHelper"; import { TexturesHelper } from "../Helpers/TexturesHelper";
import { IconButton, IconButtonConfig, IconButtonEvent } from "../Components/Ui/IconButton";
export const CustomizeSceneName = "CustomizeScene"; export const CustomizeSceneName = "CustomizeScene";
@ -35,7 +36,7 @@ export class CustomizeScene extends AbstractCharacterScene {
private bodyPartsDraggableGridLeftShadow!: Phaser.GameObjects.Image; private bodyPartsDraggableGridLeftShadow!: Phaser.GameObjects.Image;
private bodyPartsDraggableGridRightShadow!: Phaser.GameObjects.Image; private bodyPartsDraggableGridRightShadow!: Phaser.GameObjects.Image;
private bodyPartsDraggableGrid!: DraggableGrid; private bodyPartsDraggableGrid!: DraggableGrid;
private bodyPartsSlots!: Record<CustomWokaBodyPart, WokaBodyPartSlot>; private bodyPartsButtons!: Record<CustomWokaBodyPart, IconButton>;
private randomizeButton!: Button; private randomizeButton!: Button;
private finishButton!: Button; private finishButton!: Button;
@ -43,7 +44,6 @@ export class CustomizeScene extends AbstractCharacterScene {
private selectedLayers: number[] = [0, 0, 0, 0, 0, 0]; private selectedLayers: number[] = [0, 0, 0, 0, 0, 0];
private layers: BodyResourceDescriptionInterface[][] = []; private layers: BodyResourceDescriptionInterface[][] = [];
private selectedBodyPartType?: CustomWokaBodyPart; private selectedBodyPartType?: CustomWokaBodyPart;
private selectedItemTextureKey?: string;
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
@ -98,7 +98,10 @@ export class CustomizeScene extends AbstractCharacterScene {
} }
public create(): void { 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.customWokaPreviewer = new CustomWokaPreviewer(
this, this,
0, 0,
@ -126,7 +129,7 @@ export class CustomizeScene extends AbstractCharacterScene {
this.bodyPartsDraggableGridLeftShadow = this.add this.bodyPartsDraggableGridLeftShadow = this.add
.image(0, this.cameras.main.worldView.y + this.cameras.main.height, "gridEdgeShadow") .image(0, this.cameras.main.worldView.y + this.cameras.main.height, "gridEdgeShadow")
.setAlpha(1, 0, 1, 0) .setAlpha(1, 0, 1, 0)
.setOrigin(0, 1); .setOrigin(0, 0.5);
this.bodyPartsDraggableGridRightShadow = this.add this.bodyPartsDraggableGridRightShadow = this.add
.image( .image(
@ -136,38 +139,24 @@ export class CustomizeScene extends AbstractCharacterScene {
) )
.setAlpha(1, 0, 1, 0) .setAlpha(1, 0, 1, 0)
.setFlipX(true) .setFlipX(true)
.setOrigin(1, 1); .setOrigin(1, 0.5);
this.bodyPartsSlots = { this.bodyPartsButtons = {
[CustomWokaBodyPart.Hair]: new WokaBodyPartSlot(this, 0, 0, { [CustomWokaBodyPart.Accessory]: new IconButton(
...this.getDefaultWokaBodyPartSlotConfig(), this,
categoryImageKey: "iconHair", 0,
}), 0,
[CustomWokaBodyPart.Body]: new WokaBodyPartSlot(this, 0, 0, { this.getDefaultIconButtonConfig("iconAccessory")
...this.getDefaultWokaBodyPartSlotConfig(), ),
categoryImageKey: "iconBody", [CustomWokaBodyPart.Body]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconBody")),
}), [CustomWokaBodyPart.Clothes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconClothes")),
[CustomWokaBodyPart.Accessory]: new WokaBodyPartSlot(this, 0, 0, { [CustomWokaBodyPart.Eyes]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconEyes")),
...this.getDefaultWokaBodyPartSlotConfig(), [CustomWokaBodyPart.Hair]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHair")),
categoryImageKey: "iconAccessory", [CustomWokaBodyPart.Hat]: new IconButton(this, 0, 0, this.getDefaultIconButtonConfig("iconHat")),
}),
[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.selectedBodyPartType = CustomWokaBodyPart.Body; this.selectedBodyPartType = CustomWokaBodyPart.Body;
this.selectedItemTextureKey = this.layers[CustomWokaBodyPartOrder.Body][0].id; this.bodyPartsButtons.Body.select();
this.bodyPartsSlots.Body.select();
this.initializeRandomizeButton(); this.initializeRandomizeButton();
this.initializeFinishButton(); this.initializeFinishButton();
@ -185,10 +174,10 @@ export class CustomizeScene extends AbstractCharacterScene {
public onResize(): void { public onResize(): void {
this.handleCustomWokaPreviewerOnResize(); this.handleCustomWokaPreviewerOnResize();
this.handleBodyPartSlotsOnResize(); this.handleBodyPartButtonsOnResize();
this.handleBodyPartsDraggableGridOnResize();
this.handleRandomizeButtonOnResize(); this.handleRandomizeButtonOnResize();
this.handleFinishButtonOnResize(); this.handleFinishButtonOnResize();
this.handleBodyPartsDraggableGridOnResize();
} }
public nextSceneToCamera() { public nextSceneToCamera() {
@ -218,6 +207,34 @@ export class CustomizeScene extends AbstractCharacterScene {
this.scene.run(SelectCharacterSceneName); 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 { private initializeRandomizeButton(): void {
this.randomizeButton = new Button(this, 50, 50, { this.randomizeButton = new Button(this, 50, 50, {
width: 95, width: 95,
@ -275,80 +292,101 @@ export class CustomizeScene extends AbstractCharacterScene {
for (const layerItem of this.selectedLayers) { for (const layerItem of this.selectedLayers) {
const bodyPart = CustomWokaBodyPart[CustomWokaBodyPartOrder[i] as CustomWokaBodyPart]; const bodyPart = CustomWokaBodyPart[CustomWokaBodyPartOrder[i] as CustomWokaBodyPart];
this.customWokaPreviewer.updateSprite(this.layers[i][layerItem].id, bodyPart); 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; i += 1;
} }
} }
private getCurrentlySelectedWokaTexturesRecord(): Record<CustomWokaBodyPart, string> {
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 { private handleCustomWokaPreviewerOnResize(): void {
this.customWokaPreviewer.x = this.cameras.main.worldView.x + this.cameras.main.width / 2; this.customWokaPreviewer.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + 10; this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + 10;
} }
private handleBodyPartSlotsOnResize(): void { private handleBodyPartButtonsOnResize(): void {
const ratio = innerHeight / innerWidth; const ratio = innerHeight / innerWidth;
const slotDimension = 100; const slotDimension = 50;
for (const part in this.bodyPartsSlots) { for (const part in this.bodyPartsButtons) {
this.bodyPartsSlots[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension); this.bodyPartsButtons[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension);
} }
const slotSize = this.bodyPartsSlots.Accessory.displayHeight; const slotSize = this.bodyPartsButtons.Accessory.displayHeight;
if (ratio > 1.6) { if (ratio > 1.6) {
const middle = Math.floor(this.customWokaPreviewer.x); const middle = Math.floor(this.customWokaPreviewer.x);
const left = Math.floor(middle - slotSize - 10); const left = Math.floor(middle - slotSize - 23);
const right = Math.floor(middle + slotSize + 10); const right = Math.floor(middle + slotSize + 23);
const top = Math.floor( 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.bodyPartsButtons.Body.setPosition(left, top);
this.bodyPartsSlots.Eyes.setPosition(middle, top); this.bodyPartsButtons.Eyes.setPosition(middle, top);
this.bodyPartsSlots.Hair.setPosition(right, top); this.bodyPartsButtons.Hair.setPosition(right, top);
this.bodyPartsSlots.Clothes.setPosition(left, bottom); this.bodyPartsButtons.Clothes.setPosition(left, bottom);
this.bodyPartsSlots.Hat.setPosition(middle, bottom); this.bodyPartsButtons.Hat.setPosition(middle, bottom);
this.bodyPartsSlots.Accessory.setPosition(right, bottom); this.bodyPartsButtons.Accessory.setPosition(right, bottom);
return; return;
} }
const left = Math.floor( 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( 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 + 11);
const top = Math.floor(0 + slotSize * 0.5 + 9); const middle = Math.floor(top + slotSize + 24);
const middle = Math.floor(top + slotSize + 10); const bottom = Math.floor(middle + slotSize + 24);
const bottom = Math.floor(middle + slotSize + 10);
this.bodyPartsSlots.Body.setPosition(left, top); this.bodyPartsButtons.Body.setPosition(left, top);
this.bodyPartsSlots.Eyes.setPosition(left, middle); this.bodyPartsButtons.Eyes.setPosition(left, middle);
this.bodyPartsSlots.Hair.setPosition(ratio < 0.6 ? leftEdge : left, ratio < 0.6 ? middle : bottom); this.bodyPartsButtons.Hair.setPosition(left, bottom);
this.bodyPartsSlots.Clothes.setPosition(right, top); this.bodyPartsButtons.Clothes.setPosition(right, top);
this.bodyPartsSlots.Hat.setPosition(right, middle); this.bodyPartsButtons.Hat.setPosition(right, middle);
this.bodyPartsSlots.Accessory.setPosition(ratio < 0.6 ? rightEdge : right, ratio < 0.6 ? middle : bottom); this.bodyPartsButtons.Accessory.setPosition(right, bottom);
} }
private handleBodyPartsDraggableGridOnResize(): void { private handleBodyPartsDraggableGridOnResize(): void {
const gridHeight = 110; const gridHeight = 110;
const gridWidth = innerWidth / waScaleManager.getActualZoom(); 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 = { const gridPos = {
x: this.cameras.main.worldView.x + this.cameras.main.width / 2, 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.bodyPartsDraggableGridRightShadow.setPosition(
this.cameras.main.worldView.x + this.cameras.main.width, this.cameras.main.worldView.x + this.cameras.main.width,
this.cameras.main.worldView.y + this.cameras.main.height yPos
); );
try { 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 { return {
color: 0xffffff, color: 0xffffff,
borderThickness: 1, borderThickness: 1,
borderColor: 0xadafbc, borderColor: 0xadafbc,
borderSelectedColor: 0x209cee, borderSelectedColor: 0x209cee,
textureKeys: textures,
offsetX: -4, offsetX: -4,
offsetY: 2, offsetY: 2,
}; };
} }
private bindEventHandlers(): void { private bindEventHandlers(): void {
this.bindKeyboardEventHandlers();
this.events.addListener("wake", () => { this.events.addListener("wake", () => {
waScaleManager.saveZoom(); waScaleManager.saveZoom();
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1; 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.randomizeButton.on(Phaser.Input.Events.POINTER_UP, () => {
this.randomizeOutfit(); this.randomizeOutfit();
this.clearGrid(); this.clearGrid();
this.deselectAllSlots(); this.deselectAllButtons();
this.refreshPlayerCurrentOutfit(); this.refreshPlayerCurrentOutfit();
}); });
@ -435,52 +472,136 @@ export class CustomizeScene extends AbstractCharacterScene {
}); });
for (const bodyPart in CustomWokaBodyPart) { for (const bodyPart in CustomWokaBodyPart) {
const slot = this.bodyPartsSlots[bodyPart as CustomWokaBodyPart]; const button = this.bodyPartsButtons[bodyPart as CustomWokaBodyPart];
slot.on(WokaBodyPartSlotEvent.Clicked, (selected: boolean) => { button.on(IconButtonEvent.Clicked, (selected: boolean) => {
if (!selected) { if (!selected) {
this.selectedBodyPartType = bodyPart as CustomWokaBodyPart; this.selectBodyPartType(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.bodyPartsDraggableGrid.on(DraggableGridEvent.ItemClicked, (item: WokaBodyPartSlot) => { this.bodyPartsDraggableGrid.on(DraggableGridEvent.ItemClicked, (item: WokaBodyPartSlot) => {
void this.bodyPartsDraggableGrid.centerOnItem(this.bodyPartsDraggableGrid.getAllItems().indexOf(item), 500); void this.bodyPartsDraggableGrid.centerOnItem(this.bodyPartsDraggableGrid.getAllItems().indexOf(item), 500);
this.bodyPartsDraggableGrid.getAllItems().forEach((slot) => (slot as WokaBodyPartSlot).select(false)); this.deselectAllSlots();
this.changeOutfitPart(Number(item.getId()));
this.refreshPlayerCurrentOutfit();
item.select(true); item.select(true);
this.setNewBodyPart(Number(item.getId()));
}); });
} }
private selectGridItem(): WokaBodyPartSlot | undefined { private selectBodyPartType(bodyPart: CustomWokaBodyPart): void {
const items = this.bodyPartsDraggableGrid.getAllItems() as WokaBodyPartSlot[]; this.selectedBodyPartType = bodyPart;
let item: WokaBodyPartSlot | undefined; this.deselectAllButtons();
if (this.selectedBodyPartType === CustomWokaBodyPart.Body) { const button = this.bodyPartsButtons[bodyPart];
item = items.find((item) => item.getContentData().bodyImageKey === this.selectedItemTextureKey); button.select(true);
} else { this.populateGrid();
item = items.find((item) => item.getContentData().key === this.selectedItemTextureKey); 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(); item?.select();
return item; 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 { private centerGridOnItem(item: WokaBodyPartSlot, duration: number = 500): void {
void this.bodyPartsDraggableGrid.centerOnItem( void this.bodyPartsDraggableGrid.centerOnItem(
this.bodyPartsDraggableGrid.getAllItems().indexOf(item), this.bodyPartsDraggableGrid.getAllItems().indexOf(item),
@ -515,21 +636,12 @@ export class CustomizeScene extends AbstractCharacterScene {
0, 0,
0, 0,
{ {
...this.getDefaultWokaBodyPartSlotConfig(), ...this.getWokaBodyPartSlotConfig(this.selectedBodyPartType, bodyPartsLayer[i].id),
offsetX: 0, offsetX: 0,
offsetY: 0, offsetY: 0,
}, },
i i
).setDisplaySize(this.SLOT_DIMENSION, this.SLOT_DIMENSION); ).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); this.bodyPartsDraggableGrid.addItem(slot);
} }
} }
@ -538,9 +650,13 @@ export class CustomizeScene extends AbstractCharacterScene {
this.bodyPartsDraggableGrid.clearAllItems(); this.bodyPartsDraggableGrid.clearAllItems();
} }
private deselectAllSlots(): void { private deselectAllButtons(): void {
for (const bodyPart in CustomWokaBodyPart) { 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));
}
} }

View File

@ -10,8 +10,6 @@ import { chatMessagesStore, newChatMessageSubject } from "../Stores/ChatStore";
import { getIceServersConfig } from "../Components/Video/utils"; import { getIceServersConfig } from "../Components/Video/utils";
import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils"; import { isMediaBreakpointUp } from "../Utils/BreakpointsUtils";
import { SoundMeter } from "../Phaser/Components/SoundMeter"; 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 Peer from "simple-peer/simplepeer.min.js";
import { Buffer } from "buffer"; import { Buffer } from "buffer";