Merge pull request #1994 from thecodingmachine/new_custom_woka_scene
New custom woka scene
@ -5,6 +5,7 @@
|
|||||||
"license": "SEE LICENSE IN LICENSE.txt",
|
"license": "SEE LICENSE IN LICENSE.txt",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@geprog/vite-plugin-env-config": "^4.0.3",
|
"@geprog/vite-plugin-env-config": "^4.0.3",
|
||||||
|
"@home-based-studio/phaser3-utils": "^0.4.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.36",
|
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.36",
|
||||||
"@tsconfig/svelte": "^1.0.10",
|
"@tsconfig/svelte": "^1.0.10",
|
||||||
"@types/google-protobuf": "^3.7.3",
|
"@types/google-protobuf": "^3.7.3",
|
||||||
@ -45,7 +46,7 @@
|
|||||||
"easystarjs": "^0.4.4",
|
"easystarjs": "^0.4.4",
|
||||||
"generic-type-guard": "^3.4.2",
|
"generic-type-guard": "^3.4.2",
|
||||||
"google-protobuf": "^3.13.0",
|
"google-protobuf": "^3.13.0",
|
||||||
"phaser": "^3.54.0",
|
"phaser": "3.55.1",
|
||||||
"phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254",
|
"phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254",
|
||||||
"phaser3-rex-plugins": "^1.1.42",
|
"phaser3-rex-plugins": "^1.1.42",
|
||||||
"posthog-js": "^1.14.1",
|
"posthog-js": "^1.14.1",
|
||||||
|
BIN
front/public/resources/icons/icon_accessory.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
front/public/resources/icons/icon_body.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
front/public/resources/icons/icon_clothes.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
front/public/resources/icons/icon_eyes.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
front/public/resources/icons/icon_hair.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
front/public/resources/icons/icon_hat.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
front/public/resources/icons/icon_turn.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
front/public/resources/tilesets/floor_tiles.png
Normal file
After Width: | Height: | Size: 19 KiB |
@ -1,14 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Game } from "../Phaser/Game/Game";
|
import type { Game } from "../Phaser/Game/Game";
|
||||||
import { chatVisibilityStore } from "../Stores/ChatStore";
|
import { chatVisibilityStore } from "../Stores/ChatStore";
|
||||||
import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore";
|
|
||||||
import { errorStore } from "../Stores/ErrorStore";
|
import { errorStore } from "../Stores/ErrorStore";
|
||||||
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
|
import { loginSceneVisibleStore } from "../Stores/LoginSceneStore";
|
||||||
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore";
|
||||||
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore";
|
||||||
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
|
import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore";
|
||||||
import Chat from "./Chat/Chat.svelte";
|
import Chat from "./Chat/Chat.svelte";
|
||||||
import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte";
|
|
||||||
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte";
|
||||||
import LoginScene from "./Login/LoginScene.svelte";
|
import LoginScene from "./Login/LoginScene.svelte";
|
||||||
import MainLayout from "./MainLayout.svelte";
|
import MainLayout from "./MainLayout.svelte";
|
||||||
@ -31,10 +29,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<SelectCharacterScene {game} />
|
<SelectCharacterScene {game} />
|
||||||
</div>
|
</div>
|
||||||
{:else if $customCharacterSceneVisibleStore}
|
|
||||||
<div>
|
|
||||||
<CustomCharacterScene {game} />
|
|
||||||
</div>
|
|
||||||
{:else if $selectCompanionSceneVisibleStore}
|
{:else if $selectCompanionSceneVisibleStore}
|
||||||
<div>
|
<div>
|
||||||
<SelectCompanionScene {game} />
|
<SelectCompanionScene {game} />
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import type { Game } from "../../Phaser/Game/Game";
|
|
||||||
import { CustomizeScene, CustomizeSceneName } from "../../Phaser/Login/CustomizeScene";
|
|
||||||
import { activeRowStore } from "../../Stores/CustomCharacterStore";
|
|
||||||
import LL from "../../i18n/i18n-svelte";
|
|
||||||
|
|
||||||
export let game: Game;
|
|
||||||
|
|
||||||
const customCharacterScene = game.scene.getScene(CustomizeSceneName) as CustomizeScene;
|
|
||||||
|
|
||||||
function selectLeft() {
|
|
||||||
customCharacterScene.moveCursorHorizontally(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectRight() {
|
|
||||||
customCharacterScene.moveCursorHorizontally(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectUp() {
|
|
||||||
customCharacterScene.moveCursorVertically(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectDown() {
|
|
||||||
customCharacterScene.moveCursorVertically(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function previousScene() {
|
|
||||||
customCharacterScene.backToPreviousScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
function finish() {
|
|
||||||
customCharacterScene.nextSceneToCamera();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<form class="customCharacterScene">
|
|
||||||
<section class="text-center">
|
|
||||||
<h2>{$LL.woka.customWoka.title()}</h2>
|
|
||||||
</section>
|
|
||||||
<section class="action action-move">
|
|
||||||
<button
|
|
||||||
class="customCharacterSceneButton customCharacterSceneButtonLeft nes-btn"
|
|
||||||
on:click|preventDefault={selectLeft}
|
|
||||||
>
|
|
||||||
<
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="customCharacterSceneButton customCharacterSceneButtonRight nes-btn"
|
|
||||||
on:click|preventDefault={selectRight}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
<section class="action">
|
|
||||||
{#if $activeRowStore === 0}
|
|
||||||
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={previousScene}
|
|
||||||
>{$LL.woka.customWoka.navigation.return()}</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{#if $activeRowStore !== 0}
|
|
||||||
<button type="submit" class="customCharacterSceneFormBack nes-btn" on:click|preventDefault={selectUp}
|
|
||||||
>{$LL.woka.customWoka.navigation.back()}
|
|
||||||
<img src="resources/objects/arrow_up_black.png" alt="" /></button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{#if $activeRowStore === 5}
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="customCharacterSceneFormSubmit nes-btn is-primary"
|
|
||||||
on:click|preventDefault={finish}>{$LL.woka.customWoka.navigation.finish()}</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
{#if $activeRowStore !== 5}
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="customCharacterSceneFormSubmit nes-btn is-primary"
|
|
||||||
on:click|preventDefault={selectDown}
|
|
||||||
>{$LL.woka.customWoka.navigation.next()}
|
|
||||||
<img src="resources/objects/arrow_down.png" alt="" /></button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</section>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../../../style/breakpoints.scss";
|
|
||||||
|
|
||||||
form.customCharacterScene {
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
pointer-events: auto;
|
|
||||||
color: #ebeeee;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 10px;
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 55vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.customCharacterSceneButton {
|
|
||||||
position: absolute;
|
|
||||||
top: 33vh;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.customCharacterSceneFormBack {
|
|
||||||
color: #292929;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-family: "Press Start 2P";
|
|
||||||
|
|
||||||
&.customCharacterSceneButtonLeft {
|
|
||||||
left: 33vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.customCharacterSceneButtonRight {
|
|
||||||
right: 33vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
form.customCharacterScene button.customCharacterSceneButtonLeft {
|
|
||||||
left: 5vw;
|
|
||||||
}
|
|
||||||
form.customCharacterScene button.customCharacterSceneButtonRight {
|
|
||||||
right: 5vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
184
front/src/Phaser/Components/CustomizeWoka/CustomWokaPreviewer.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import { Easing } from "../../../types";
|
||||||
|
import { getPlayerAnimations, PlayerAnimationDirections, PlayerAnimationTypes } from "../../Player/Animation";
|
||||||
|
|
||||||
|
export enum CustomWokaBodyPart {
|
||||||
|
Body = "Body",
|
||||||
|
Eyes = "Eyes",
|
||||||
|
Hair = "Hair",
|
||||||
|
Clothes = "Clothes",
|
||||||
|
Hat = "Hat",
|
||||||
|
Accessory = "Accessory",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CustomWokaBodyPartOrder {
|
||||||
|
Body,
|
||||||
|
Eyes,
|
||||||
|
Hair,
|
||||||
|
Clothes,
|
||||||
|
Hat,
|
||||||
|
Accessory,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomWokaPreviewerConfig {
|
||||||
|
color: number;
|
||||||
|
borderThickness: number;
|
||||||
|
borderColor: number;
|
||||||
|
bodyPartsOffsetX: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomWokaPreviewer extends Phaser.GameObjects.Container {
|
||||||
|
private background: Phaser.GameObjects.Image;
|
||||||
|
private frame: Phaser.GameObjects.Graphics;
|
||||||
|
private sprites: Record<CustomWokaBodyPart, Phaser.GameObjects.Sprite>;
|
||||||
|
private turnIcon: Phaser.GameObjects.Image;
|
||||||
|
|
||||||
|
private animationDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
||||||
|
private moving: boolean = true;
|
||||||
|
|
||||||
|
private turnIconTween?: Phaser.Tweens.Tween;
|
||||||
|
|
||||||
|
private config: CustomWokaPreviewerConfig;
|
||||||
|
|
||||||
|
public readonly SIZE: number = 50;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, config: CustomWokaPreviewerConfig) {
|
||||||
|
super(scene, x, y);
|
||||||
|
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
this.sprites = {
|
||||||
|
[CustomWokaBodyPart.Accessory]: this.scene.add
|
||||||
|
.sprite(this.config.bodyPartsOffsetX, 0, "")
|
||||||
|
.setVisible(false),
|
||||||
|
[CustomWokaBodyPart.Body]: this.scene.add.sprite(this.config.bodyPartsOffsetX, 0, "").setVisible(false),
|
||||||
|
[CustomWokaBodyPart.Clothes]: this.scene.add.sprite(this.config.bodyPartsOffsetX, 0, "").setVisible(false),
|
||||||
|
[CustomWokaBodyPart.Eyes]: this.scene.add.sprite(this.config.bodyPartsOffsetX, 0, "").setVisible(false),
|
||||||
|
[CustomWokaBodyPart.Hair]: 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, "floorTexture1");
|
||||||
|
this.frame = this.scene.add.graphics();
|
||||||
|
this.turnIcon = this.scene.add
|
||||||
|
.image(this.background.displayWidth * 0.35, this.background.displayHeight * 0.35, "iconTurn")
|
||||||
|
.setScale(0.25)
|
||||||
|
.setTintFill(0xffffff)
|
||||||
|
.setAlpha(0.5);
|
||||||
|
|
||||||
|
this.drawFrame();
|
||||||
|
this.setSize(this.SIZE, this.SIZE);
|
||||||
|
this.setInteractive({ cursor: "pointer" });
|
||||||
|
|
||||||
|
this.add([
|
||||||
|
this.background,
|
||||||
|
this.frame,
|
||||||
|
this.sprites.Body,
|
||||||
|
this.sprites.Eyes,
|
||||||
|
this.sprites.Hair,
|
||||||
|
this.sprites.Clothes,
|
||||||
|
this.sprites.Hat,
|
||||||
|
this.sprites.Accessory,
|
||||||
|
this.turnIcon,
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.bindEventHandlers();
|
||||||
|
|
||||||
|
this.scene.add.existing(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(): void {
|
||||||
|
this.animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public changeAnimation(direction: PlayerAnimationDirections, moving: boolean): void {
|
||||||
|
this.animationDirection = direction;
|
||||||
|
this.moving = moving;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSprite(textureKey: string, bodyPart: CustomWokaBodyPart): void {
|
||||||
|
this.sprites[bodyPart].anims.stop();
|
||||||
|
this.sprites[bodyPart].setTexture(textureKey).setVisible(textureKey !== "");
|
||||||
|
if (textureKey === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getPlayerAnimations(textureKey).forEach((d) => {
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: d.key,
|
||||||
|
frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }),
|
||||||
|
frameRate: d.frameRate,
|
||||||
|
repeat: d.repeat,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Needed, otherwise, animations are not handled correctly.
|
||||||
|
if (this.scene) {
|
||||||
|
this.scene.sys.updateList.add(this.sprites[bodyPart]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public isMoving(): boolean {
|
||||||
|
return this.moving;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAnimationDirection(): PlayerAnimationDirections {
|
||||||
|
return this.animationDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bindEventHandlers(): void {
|
||||||
|
this.on(Phaser.Input.Events.POINTER_UP, () => {
|
||||||
|
const direction = this.getNextAnimationDirection();
|
||||||
|
const moving = direction === PlayerAnimationDirections.Down ? !this.moving : this.moving;
|
||||||
|
this.changeAnimation(direction, moving);
|
||||||
|
|
||||||
|
this.turnIconTween?.stop();
|
||||||
|
this.turnIcon.setScale(0.25);
|
||||||
|
this.turnIconTween = this.scene.tweens.add({
|
||||||
|
targets: [this.turnIcon],
|
||||||
|
duration: 100,
|
||||||
|
scale: 0.2,
|
||||||
|
yoyo: true,
|
||||||
|
ease: Easing.SineEaseIn,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private drawFrame(): void {
|
||||||
|
this.frame.clear();
|
||||||
|
this.frame.lineStyle(this.config.borderThickness, 0xadafbc);
|
||||||
|
this.frame.strokeRect(-this.SIZE / 2, -this.SIZE / 2, this.SIZE, this.SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private animate(): void {
|
||||||
|
for (const bodyPartKey in this.sprites) {
|
||||||
|
const sprite = this.sprites[bodyPartKey as CustomWokaBodyPart];
|
||||||
|
if (!sprite.anims) {
|
||||||
|
console.error("ANIMS IS NOT DEFINED!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const textureKey = sprite.texture.key;
|
||||||
|
if (textureKey === "__MISSING") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.moving &&
|
||||||
|
(!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== this.animationDirection)
|
||||||
|
) {
|
||||||
|
sprite.play(textureKey + "-" + this.animationDirection + "-" + PlayerAnimationTypes.Walk, true);
|
||||||
|
} else if (!this.moving) {
|
||||||
|
sprite.anims.play(textureKey + "-" + this.animationDirection + "-" + PlayerAnimationTypes.Idle, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNextAnimationDirection(): PlayerAnimationDirections {
|
||||||
|
switch (this.animationDirection) {
|
||||||
|
case PlayerAnimationDirections.Down:
|
||||||
|
return PlayerAnimationDirections.Left;
|
||||||
|
case PlayerAnimationDirections.Left:
|
||||||
|
return PlayerAnimationDirections.Up;
|
||||||
|
case PlayerAnimationDirections.Up:
|
||||||
|
return PlayerAnimationDirections.Right;
|
||||||
|
case PlayerAnimationDirections.Right:
|
||||||
|
return PlayerAnimationDirections.Down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
143
front/src/Phaser/Components/CustomizeWoka/WokaBodyPartSlot.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
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;
|
||||||
|
borderThickness: number;
|
||||||
|
borderColor: number;
|
||||||
|
borderSelectedColor: number;
|
||||||
|
offsetX: number;
|
||||||
|
offsetY: number;
|
||||||
|
textureKeys: Record<CustomWokaBodyPart, string>;
|
||||||
|
categoryImageKey?: string;
|
||||||
|
selected?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WokaBodyPartSlotEvent {
|
||||||
|
Clicked = "WokaBodyPartSlotEvent:Clicked",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WokaBodyPartSlot extends GridItem {
|
||||||
|
private background: Phaser.GameObjects.Image;
|
||||||
|
private frame: Phaser.GameObjects.Graphics;
|
||||||
|
private categoryImage?: Phaser.GameObjects.Image;
|
||||||
|
private sprites: Record<CustomWokaBodyPart, Phaser.GameObjects.Sprite>;
|
||||||
|
|
||||||
|
private config: WokaBodyPartSlotConfig;
|
||||||
|
|
||||||
|
private selected: boolean;
|
||||||
|
|
||||||
|
public static readonly SIZE: number = 50;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, config: WokaBodyPartSlotConfig, id?: number) {
|
||||||
|
super(scene, `${id}`, { x, y });
|
||||||
|
|
||||||
|
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, `floorTexture1`);
|
||||||
|
this.frame = this.scene.add.graphics();
|
||||||
|
this.drawFrame();
|
||||||
|
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
|
||||||
|
.image(WokaBodyPartSlot.SIZE / 2 - 1, -WokaBodyPartSlot.SIZE / 2 + 1, this.config.categoryImageKey)
|
||||||
|
.setDisplaySize(16, 16)
|
||||||
|
.setAlpha(0.75)
|
||||||
|
.setOrigin(1, 0);
|
||||||
|
this.add(this.categoryImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setSize(WokaBodyPartSlot.SIZE, WokaBodyPartSlot.SIZE);
|
||||||
|
this.setInteractive({ cursor: "pointer" });
|
||||||
|
this.scene.input.setDraggable(this);
|
||||||
|
|
||||||
|
this.bindEventHandlers();
|
||||||
|
|
||||||
|
this.scene.add.existing(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getContentData(): Record<CustomWokaBodyPart, string> {
|
||||||
|
return this.config.textureKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setTextures(textureKeys: Record<CustomWokaBodyPart, string>): 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 {
|
||||||
|
if (this.selected === select) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selected = select;
|
||||||
|
this.updateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isSelected(): boolean {
|
||||||
|
return this.selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bindEventHandlers(): void {
|
||||||
|
super.bindEventHandlers();
|
||||||
|
|
||||||
|
this.on(GridItemEvent.Clicked, () => {
|
||||||
|
this.emit(WokaBodyPartSlotEvent.Clicked, this.selected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private drawFrame(): void {
|
||||||
|
this.frame.clear();
|
||||||
|
this.frame.lineStyle(
|
||||||
|
this.config.borderThickness,
|
||||||
|
this.selected ? this.config.borderSelectedColor : this.config.borderColor
|
||||||
|
);
|
||||||
|
|
||||||
|
const size = WokaBodyPartSlot.SIZE;
|
||||||
|
|
||||||
|
this.frame.strokeRect(-size / 2, -size / 2, size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateSelected(): void {
|
||||||
|
this.drawFrame();
|
||||||
|
}
|
||||||
|
}
|
99
front/src/Phaser/Components/Ui/Button.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
export interface ButtonConfig {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
idle: ButtonAppearanceConfig;
|
||||||
|
hover: ButtonAppearanceConfig;
|
||||||
|
pressed: ButtonAppearanceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ButtonAppearanceConfig {
|
||||||
|
textColor: string;
|
||||||
|
color: number;
|
||||||
|
borderThickness: number;
|
||||||
|
borderColor: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Button extends Phaser.GameObjects.Container {
|
||||||
|
private background: Phaser.GameObjects.Graphics;
|
||||||
|
private text: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
|
private config: ButtonConfig;
|
||||||
|
|
||||||
|
private hovered: boolean = false;
|
||||||
|
private pressed: boolean = false;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, config: ButtonConfig) {
|
||||||
|
super(scene, x, y);
|
||||||
|
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
this.background = this.scene.add.graphics();
|
||||||
|
this.text = this.scene.add
|
||||||
|
.text(0, 0, "", {
|
||||||
|
color: "0x000000",
|
||||||
|
fontFamily: '"Press Start 2P"',
|
||||||
|
fontSize: "9px",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5, 0.45);
|
||||||
|
this.drawBackground(this.config.idle);
|
||||||
|
|
||||||
|
this.add([this.background, this.text]);
|
||||||
|
|
||||||
|
this.setSize(this.config.width, this.config.height);
|
||||||
|
this.setInteractive({ cursor: "pointer" });
|
||||||
|
|
||||||
|
this.bindEventHandlers();
|
||||||
|
|
||||||
|
this.scene.add.existing(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setText(text: string): void {
|
||||||
|
this.text.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateButtonAppearance(): void {
|
||||||
|
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: ButtonAppearanceConfig): 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);
|
||||||
|
|
||||||
|
this.text.setColor(appearance.textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bindEventHandlers(): void {
|
||||||
|
this.on(Phaser.Input.Events.POINTER_OVER, () => {
|
||||||
|
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, () => {
|
||||||
|
this.pressed = true;
|
||||||
|
this.updateButtonAppearance();
|
||||||
|
});
|
||||||
|
this.on(Phaser.Input.Events.POINTER_UP, () => {
|
||||||
|
this.pressed = false;
|
||||||
|
this.updateButtonAppearance();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
115
front/src/Phaser/Components/Ui/IconButton.ts
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,9 @@
|
|||||||
import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation";
|
import {
|
||||||
|
AnimationData,
|
||||||
|
getPlayerAnimations,
|
||||||
|
PlayerAnimationDirections,
|
||||||
|
PlayerAnimationTypes,
|
||||||
|
} from "../Player/Animation";
|
||||||
import { SpeechBubble } from "./SpeechBubble";
|
import { SpeechBubble } from "./SpeechBubble";
|
||||||
import Text = Phaser.GameObjects.Text;
|
import Text = Phaser.GameObjects.Text;
|
||||||
import Container = Phaser.GameObjects.Container;
|
import Container = Phaser.GameObjects.Container;
|
||||||
@ -21,15 +26,6 @@ import { TalkIcon } from "../Components/TalkIcon";
|
|||||||
import { Deferred } from "ts-deferred";
|
import { Deferred } from "ts-deferred";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
|
|
||||||
interface AnimationData {
|
|
||||||
key: string;
|
|
||||||
frameRate: number;
|
|
||||||
repeat: number;
|
|
||||||
frameModel: string; //todo use an enum
|
|
||||||
frames: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const interactiveRadius = 35;
|
const interactiveRadius = 35;
|
||||||
|
|
||||||
export abstract class Character extends Container implements OutlineableInterface {
|
export abstract class Character extends Container implements OutlineableInterface {
|
||||||
@ -248,7 +244,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTextures(textures: string[], frame?: string | number): void {
|
private addTextures(textures: string[], frame?: string | number): void {
|
||||||
if (textures.length < 1) {
|
if (textures.length < 1) {
|
||||||
throw new TextureError("no texture given");
|
throw new TextureError("no texture given");
|
||||||
}
|
}
|
||||||
@ -259,7 +255,7 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
}
|
}
|
||||||
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
||||||
this.add(sprite);
|
this.add(sprite);
|
||||||
this.getPlayerAnimations(texture).forEach((d) => {
|
getPlayerAnimations(texture).forEach((d) => {
|
||||||
this.scene.anims.create({
|
this.scene.anims.create({
|
||||||
key: d.key,
|
key: d.key,
|
||||||
frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }),
|
frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }),
|
||||||
@ -279,67 +275,6 @@ export abstract class Character extends Container implements OutlineableInterfac
|
|||||||
return this.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined;
|
return this.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPlayerAnimations(name: string): AnimationData[] {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [0, 1, 2, 1],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [3, 4, 5, 4],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [6, 7, 8, 7],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [9, 10, 11, 10],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [1],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [4],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [7],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`,
|
|
||||||
frameModel: name,
|
|
||||||
frames: [10],
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected playAnimation(direction: PlayerAnimationDirections, moving: boolean): void {
|
protected playAnimation(direction: PlayerAnimationDirections, moving: boolean): void {
|
||||||
if (this.invisible) return;
|
if (this.invisible) return;
|
||||||
for (const [texture, sprite] of this.sprites.entries()) {
|
for (const [texture, sprite] of this.sprites.entries()) {
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import Container = Phaser.GameObjects.Container;
|
|
||||||
import type { Scene } from "phaser";
|
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sprite of a customized character (used in the Customize Scene only)
|
|
||||||
*/
|
|
||||||
export class CustomizedCharacter extends Container {
|
|
||||||
public constructor(scene: Scene, x: number, y: number, layers: string[]) {
|
|
||||||
super(scene, x, y);
|
|
||||||
this.updateSprites(layers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateSprites(layers: string[]): void {
|
|
||||||
this.removeAll(true);
|
|
||||||
for (const layer of layers) {
|
|
||||||
this.add(new Sprite(this.scene, 0, 0, layer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,4 +31,40 @@ export class TexturesHelper {
|
|||||||
throw new Error("Could not get the snapshot");
|
throw new Error("Could not get the snapshot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static createFloorRectangleTexture(
|
||||||
|
scene: Phaser.Scene,
|
||||||
|
newTextureKey: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
sourceTextureKey: string,
|
||||||
|
sourceTextureFrame?: number | string,
|
||||||
|
sourceTextureWidth: number = 32,
|
||||||
|
sourceTextureHeight: number = 32
|
||||||
|
): void {
|
||||||
|
const rt = scene.make.renderTexture({ x: 0, y: 0, width, height }, false);
|
||||||
|
const widthTiles = Math.ceil(width / sourceTextureWidth);
|
||||||
|
const heightTiles = Math.ceil(height / sourceTextureHeight);
|
||||||
|
|
||||||
|
for (let x = 0; x < widthTiles; x += 1) {
|
||||||
|
for (let y = 0; y < heightTiles; y += 1) {
|
||||||
|
rt.drawFrame(sourceTextureKey, sourceTextureFrame, x * 32, y * 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.saveTexture(newTextureKey);
|
||||||
|
rt.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static createRectangleTexture(
|
||||||
|
scene: Phaser.Scene,
|
||||||
|
textureKey: string,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
color: number
|
||||||
|
): void {
|
||||||
|
const rectangleTexture = scene.add.graphics().fillStyle(color, 1).fillRect(0, 0, width, height);
|
||||||
|
rectangleTexture.generateTexture(textureKey, width, height);
|
||||||
|
rectangleTexture.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
import { BodyResourceDescriptionInterface, PlayerTexturesKey } from "../Entity/PlayerTextures";
|
|
||||||
import { loadWokaTexture } from "../Entity/PlayerTexturesLoadingManager";
|
|
||||||
import type CancelablePromise from "cancelable-promise";
|
|
||||||
import { PlayerTextures } from "../Entity/PlayerTextures";
|
import { PlayerTextures } from "../Entity/PlayerTextures";
|
||||||
import Texture = Phaser.Textures.Texture;
|
|
||||||
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
import { SuperLoaderPlugin } from "../Services/SuperLoaderPlugin";
|
||||||
|
|
||||||
export abstract class AbstractCharacterScene extends ResizableScene {
|
export abstract class AbstractCharacterScene extends ResizableScene {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { EnableCameraSceneName } from "./EnableCameraScene";
|
import { EnableCameraSceneName } from "./EnableCameraScene";
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
|
||||||
import { loadAllLayers } from "../Entity/PlayerTexturesLoadingManager";
|
import { loadAllLayers } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
|
||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
import { Loader } from "../Components/Loader";
|
import { Loader } from "../Components/Loader";
|
||||||
@ -9,31 +7,50 @@ import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures"
|
|||||||
import { AbstractCharacterScene } from "./AbstractCharacterScene";
|
import { AbstractCharacterScene } from "./AbstractCharacterScene";
|
||||||
import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
import { areCharacterLayersValid } from "../../Connexion/LocalUser";
|
||||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||||
import { activeRowStore, customCharacterSceneVisibleStore } from "../../Stores/CustomCharacterStore";
|
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import { CustomizedCharacter } from "../Entity/CustomizedCharacter";
|
|
||||||
import { get } from "svelte/store";
|
|
||||||
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
import { analyticsClient } from "../../Administration/AnalyticsClient";
|
||||||
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
import { isMediaBreakpointUp } from "../../Utils/BreakpointsUtils";
|
||||||
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
import { PUSHER_URL } from "../../Enum/EnvironmentVariable";
|
||||||
|
import {
|
||||||
|
CustomWokaBodyPart,
|
||||||
|
CustomWokaBodyPartOrder,
|
||||||
|
CustomWokaPreviewer,
|
||||||
|
CustomWokaPreviewerConfig,
|
||||||
|
} from "../Components/CustomizeWoka/CustomWokaPreviewer";
|
||||||
|
import { DraggableGrid } from "@home-based-studio/phaser3-utils";
|
||||||
|
import {
|
||||||
|
WokaBodyPartSlot,
|
||||||
|
WokaBodyPartSlotConfig,
|
||||||
|
WokaBodyPartSlotEvent,
|
||||||
|
} from "../Components/CustomizeWoka/WokaBodyPartSlot";
|
||||||
|
import { DraggableGridEvent } from "@home-based-studio/phaser3-utils/lib/utils/gui/containers/grids/DraggableGrid";
|
||||||
|
import { Button } from "../Components/Ui/Button";
|
||||||
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
|
import { wokaList } from "../../Messages/JsonMessages/PlayerTextures";
|
||||||
|
import { TexturesHelper } from "../Helpers/TexturesHelper";
|
||||||
|
import { IconButton, IconButtonConfig, IconButtonEvent } from "../Components/Ui/IconButton";
|
||||||
|
|
||||||
export const CustomizeSceneName = "CustomizeScene";
|
export const CustomizeSceneName = "CustomizeScene";
|
||||||
|
|
||||||
export class CustomizeScene extends AbstractCharacterScene {
|
export class CustomizeScene extends AbstractCharacterScene {
|
||||||
private Rectangle!: Rectangle;
|
private customWokaPreviewer!: CustomWokaPreviewer;
|
||||||
|
private bodyPartsDraggableGridLeftShadow!: Phaser.GameObjects.Image;
|
||||||
|
private bodyPartsDraggableGridRightShadow!: Phaser.GameObjects.Image;
|
||||||
|
private bodyPartsDraggableGrid!: DraggableGrid;
|
||||||
|
private bodyPartsButtons!: Record<CustomWokaBodyPart, IconButton>;
|
||||||
|
|
||||||
private selectedLayers: number[] = [0];
|
private randomizeButton!: Button;
|
||||||
private containersRow: CustomizedCharacter[][] = [];
|
private finishButton!: Button;
|
||||||
|
|
||||||
|
private selectedLayers: number[] = [0, 0, 0, 0, 0, 0];
|
||||||
private layers: BodyResourceDescriptionInterface[][] = [];
|
private layers: BodyResourceDescriptionInterface[][] = [];
|
||||||
|
private selectedBodyPartType?: CustomWokaBodyPart;
|
||||||
|
|
||||||
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
||||||
|
|
||||||
private moveHorizontally: number = 0;
|
|
||||||
private moveVertically: number = 0;
|
|
||||||
|
|
||||||
private loader: Loader;
|
private loader: Loader;
|
||||||
|
|
||||||
|
private readonly SLOT_DIMENSION = 100;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
key: CustomizeSceneName,
|
key: CustomizeSceneName,
|
||||||
@ -41,7 +58,20 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
this.loader = new Loader(this);
|
this.loader = new Loader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
public preload(): void {
|
||||||
|
this.input.dragDistanceThreshold = 10;
|
||||||
|
|
||||||
|
this.load.image("iconClothes", "/resources/icons/icon_clothes.png");
|
||||||
|
this.load.image("iconAccessory", "/resources/icons/icon_accessory.png");
|
||||||
|
this.load.image("iconHat", "/resources/icons/icon_hat.png");
|
||||||
|
this.load.image("iconHair", "/resources/icons/icon_hair.png");
|
||||||
|
this.load.image("iconEyes", "/resources/icons/icon_eyes.png");
|
||||||
|
this.load.image("iconBody", "/resources/icons/icon_body.png");
|
||||||
|
this.load.image("iconTurn", "/resources/icons/icon_turn.png");
|
||||||
|
this.load.spritesheet("floorTiles", "/resources/tilesets/floor_tiles.png", { frameWidth: 32, frameHeight: 32 });
|
||||||
|
|
||||||
|
TexturesHelper.createRectangleTexture(this, "gridEdgeShadow", this.cameras.main.width * 0.2, 115, 0x000000);
|
||||||
|
|
||||||
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
|
const wokaMetadataKey = "woka-list" + gameManager.currentStartedRoom.href;
|
||||||
this.cache.json.remove(wokaMetadataKey);
|
this.cache.json.remove(wokaMetadataKey);
|
||||||
this.superLoad
|
this.superLoad
|
||||||
@ -68,212 +98,87 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
this.loader.addLoader();
|
this.loader.addLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
public create(): void {
|
||||||
customCharacterSceneVisibleStore.set(true);
|
TexturesHelper.createFloorRectangleTexture(this, "floorTexture1", 50, 50, "floorTiles", 0);
|
||||||
this.events.addListener("wake", () => {
|
TexturesHelper.createFloorRectangleTexture(this, "floorTexture2", 50, 50, "floorTiles", 1);
|
||||||
waScaleManager.saveZoom();
|
TexturesHelper.createFloorRectangleTexture(this, "floorTexture3", 50, 50, "floorTiles", 2);
|
||||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
|
TexturesHelper.createFloorRectangleTexture(this, "floorTexture4", 50, 50, "floorTiles", 3);
|
||||||
customCharacterSceneVisibleStore.set(true);
|
this.customWokaPreviewer = new CustomWokaPreviewer(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
this.getCustomWokaPreviewerConfig()
|
||||||
|
).setDisplaySize(200, 200);
|
||||||
|
|
||||||
|
this.bodyPartsDraggableGrid = new DraggableGrid(this, {
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
maskPosition: { x: 0, y: 0 },
|
||||||
|
dimension: { x: 485, y: 165 },
|
||||||
|
horizontal: true,
|
||||||
|
repositionToCenter: true,
|
||||||
|
itemsInRow: 1,
|
||||||
|
margin: {
|
||||||
|
left: (innerWidth / waScaleManager.getActualZoom() - this.SLOT_DIMENSION) * 0.5,
|
||||||
|
right: (innerWidth / waScaleManager.getActualZoom() - this.SLOT_DIMENSION) * 0.5,
|
||||||
|
},
|
||||||
|
spacing: 5,
|
||||||
|
debug: {
|
||||||
|
showDraggableSpace: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
waScaleManager.saveZoom();
|
this.bodyPartsDraggableGridLeftShadow = this.add
|
||||||
waScaleManager.zoomModifier = isMediaBreakpointUp("md") ? 3 : 1;
|
.image(0, this.cameras.main.worldView.y + this.cameras.main.height, "gridEdgeShadow")
|
||||||
|
.setAlpha(1, 0, 1, 0)
|
||||||
|
.setOrigin(0, 0.5);
|
||||||
|
|
||||||
this.Rectangle = this.add.rectangle(
|
this.bodyPartsDraggableGridRightShadow = this.add
|
||||||
this.cameras.main.worldView.x + this.cameras.main.width / 2,
|
.image(
|
||||||
this.cameras.main.worldView.y + this.cameras.main.height / 3,
|
this.cameras.main.worldView.x + this.cameras.main.width,
|
||||||
32,
|
this.cameras.main.worldView.y + this.cameras.main.height,
|
||||||
33
|
"gridEdgeShadow"
|
||||||
);
|
)
|
||||||
this.Rectangle.setStrokeStyle(2, 0xffffff);
|
.setAlpha(1, 0, 1, 0)
|
||||||
this.add.existing(this.Rectangle);
|
.setFlipX(true)
|
||||||
|
.setOrigin(1, 0.5);
|
||||||
|
|
||||||
this.createCustomizeLayer(0, 0, 0);
|
this.bodyPartsButtons = {
|
||||||
this.createCustomizeLayer(0, 0, 1);
|
[CustomWokaBodyPart.Accessory]: new IconButton(
|
||||||
this.createCustomizeLayer(0, 0, 2);
|
this,
|
||||||
this.createCustomizeLayer(0, 0, 3);
|
0,
|
||||||
this.createCustomizeLayer(0, 0, 4);
|
0,
|
||||||
this.createCustomizeLayer(0, 0, 5);
|
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.moveLayers();
|
this.selectedBodyPartType = CustomWokaBodyPart.Body;
|
||||||
this.input.keyboard.on("keyup-ENTER", () => {
|
this.bodyPartsButtons.Body.select();
|
||||||
this.nextSceneToCamera();
|
|
||||||
});
|
|
||||||
this.input.keyboard.on("keyup-BACKSPACE", () => {
|
|
||||||
this.backToPreviousScene();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Note: the key bindings are not directly put on the moveCursorVertically or moveCursorHorizontally methods
|
this.initializeRandomizeButton();
|
||||||
// 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
|
this.initializeFinishButton();
|
||||||
// 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();
|
this.refreshPlayerCurrentOutfit();
|
||||||
if (customCursorPosition) {
|
|
||||||
activeRowStore.set(customCursorPosition.activeRow);
|
|
||||||
this.selectedLayers = customCursorPosition.selectedLayers;
|
|
||||||
this.moveLayers();
|
|
||||||
this.updateSelectedLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onResize();
|
this.onResize();
|
||||||
|
|
||||||
|
this.bindEventHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public moveCursorHorizontally(index: number): void {
|
public update(time: number, dt: number): void {
|
||||||
this.moveHorizontally = index;
|
this.customWokaPreviewer.update();
|
||||||
}
|
|
||||||
|
|
||||||
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<string> {
|
|
||||||
const children: Array<string> = new Array<string>();
|
|
||||||
for (let j = 0; j <= layerNumber; j++) {
|
|
||||||
if (j === layerNumber) {
|
|
||||||
children.push(this.layers[j][selectedItem].id);
|
|
||||||
} else {
|
|
||||||
const layer = this.selectedLayers[j];
|
|
||||||
if (layer === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
children.push(this.layers[j][layer].id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
public onResize(): void {
|
||||||
this.moveLayers();
|
this.handleCustomWokaPreviewerOnResize();
|
||||||
|
this.handleBodyPartButtonsOnResize();
|
||||||
this.Rectangle.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
|
this.handleRandomizeButtonOnResize();
|
||||||
this.Rectangle.y = this.cameras.main.worldView.y + this.cameras.main.height / 3;
|
this.handleFinishButtonOnResize();
|
||||||
|
this.handleBodyPartsDraggableGridOnResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public nextSceneToCamera() {
|
public nextSceneToCamera() {
|
||||||
@ -295,13 +200,464 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||||||
this.scene.stop(CustomizeSceneName);
|
this.scene.stop(CustomizeSceneName);
|
||||||
waScaleManager.restoreZoom();
|
waScaleManager.restoreZoom();
|
||||||
gameManager.tryResumingGame(EnableCameraSceneName);
|
gameManager.tryResumingGame(EnableCameraSceneName);
|
||||||
customCharacterSceneVisibleStore.set(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public backToPreviousScene() {
|
public backToPreviousScene() {
|
||||||
this.scene.stop(CustomizeSceneName);
|
this.scene.stop(CustomizeSceneName);
|
||||||
waScaleManager.restoreZoom();
|
waScaleManager.restoreZoom();
|
||||||
this.scene.run(SelectCharacterSceneName);
|
this.scene.run(SelectCharacterSceneName);
|
||||||
customCharacterSceneVisibleStore.set(false);
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
height: 50,
|
||||||
|
idle: {
|
||||||
|
color: 0xffffff,
|
||||||
|
textColor: "#000000",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0xe7e7e7,
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
color: 0xe7e7e7,
|
||||||
|
textColor: "#000000",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0xadafbc,
|
||||||
|
},
|
||||||
|
pressed: {
|
||||||
|
color: 0xadafbc,
|
||||||
|
textColor: "#000000",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0xadafbc,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.randomizeButton.setText("Randomize");
|
||||||
|
}
|
||||||
|
|
||||||
|
private initializeFinishButton(): void {
|
||||||
|
this.finishButton = new Button(this, 50, 50, {
|
||||||
|
width: 95,
|
||||||
|
height: 50,
|
||||||
|
idle: {
|
||||||
|
color: 0x209cee,
|
||||||
|
textColor: "#ffffff",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0x006bb3,
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
color: 0x0987db,
|
||||||
|
textColor: "#ffffff",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0x006bb3,
|
||||||
|
},
|
||||||
|
pressed: {
|
||||||
|
color: 0x006bb3,
|
||||||
|
textColor: "#ffffff",
|
||||||
|
borderThickness: 3,
|
||||||
|
borderColor: 0x006bb3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.finishButton.setText("Finish");
|
||||||
|
}
|
||||||
|
|
||||||
|
private refreshPlayerCurrentOutfit(): void {
|
||||||
|
let i = 0;
|
||||||
|
for (const layerItem of this.selectedLayers) {
|
||||||
|
const bodyPart = CustomWokaBodyPart[CustomWokaBodyPartOrder[i] as CustomWokaBodyPart];
|
||||||
|
this.customWokaPreviewer.updateSprite(this.layers[i][layerItem].id, bodyPart);
|
||||||
|
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 {
|
||||||
|
this.customWokaPreviewer.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
|
||||||
|
this.customWokaPreviewer.y = this.customWokaPreviewer.displayHeight * 0.5 + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleBodyPartButtonsOnResize(): void {
|
||||||
|
const ratio = innerHeight / innerWidth;
|
||||||
|
const slotDimension = 50;
|
||||||
|
|
||||||
|
for (const part in this.bodyPartsButtons) {
|
||||||
|
this.bodyPartsButtons[part as CustomWokaBodyPart].setDisplaySize(slotDimension, slotDimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
const slotSize = this.bodyPartsButtons.Accessory.displayHeight;
|
||||||
|
|
||||||
|
if (ratio > 1.6) {
|
||||||
|
const middle = Math.floor(this.customWokaPreviewer.x);
|
||||||
|
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 + 30
|
||||||
|
);
|
||||||
|
const bottom = Math.floor(top + slotSize + 23);
|
||||||
|
|
||||||
|
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 - 24
|
||||||
|
);
|
||||||
|
const right = Math.floor(
|
||||||
|
this.customWokaPreviewer.x + this.customWokaPreviewer.displayWidth * 0.5 + slotSize * 0.5 + 24
|
||||||
|
);
|
||||||
|
const top = Math.floor(0 + slotSize * 0.5 + 11);
|
||||||
|
const middle = Math.floor(top + slotSize + 24);
|
||||||
|
const bottom = Math.floor(middle + slotSize + 24);
|
||||||
|
|
||||||
|
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: yPos,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.bodyPartsDraggableGridLeftShadow.setPosition(0, yPos);
|
||||||
|
this.bodyPartsDraggableGridRightShadow.setPosition(
|
||||||
|
this.cameras.main.worldView.x + this.cameras.main.width,
|
||||||
|
yPos
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.bodyPartsDraggableGrid.changeDraggableSpacePosAndSize(
|
||||||
|
gridPos,
|
||||||
|
{ x: gridWidth, y: gridHeight },
|
||||||
|
gridPos
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populateGrid();
|
||||||
|
const selectedGridItem = this.selectGridItem();
|
||||||
|
if (selectedGridItem) {
|
||||||
|
this.centerGridOnItem(selectedGridItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRandomizeButtonOnResize(): void {
|
||||||
|
const x =
|
||||||
|
this.customWokaPreviewer.x +
|
||||||
|
(this.customWokaPreviewer.displayWidth - this.randomizeButton.displayWidth) * 0.5;
|
||||||
|
const y =
|
||||||
|
this.customWokaPreviewer.y +
|
||||||
|
(this.customWokaPreviewer.displayHeight + this.randomizeButton.displayHeight) * 0.5 +
|
||||||
|
10;
|
||||||
|
this.randomizeButton.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleFinishButtonOnResize(): void {
|
||||||
|
const x =
|
||||||
|
this.customWokaPreviewer.x -
|
||||||
|
(this.customWokaPreviewer.displayWidth - this.randomizeButton.displayWidth) * 0.5;
|
||||||
|
const y =
|
||||||
|
this.customWokaPreviewer.y +
|
||||||
|
(this.customWokaPreviewer.displayHeight + this.randomizeButton.displayHeight) * 0.5 +
|
||||||
|
10;
|
||||||
|
this.finishButton.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCustomWokaPreviewerConfig(): CustomWokaPreviewerConfig {
|
||||||
|
return {
|
||||||
|
color: 0xffffff,
|
||||||
|
borderThickness: 1,
|
||||||
|
borderColor: 0xadafbc,
|
||||||
|
bodyPartsOffsetX: -1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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.randomizeButton.on(Phaser.Input.Events.POINTER_UP, () => {
|
||||||
|
this.randomizeOutfit();
|
||||||
|
this.clearGrid();
|
||||||
|
this.deselectAllButtons();
|
||||||
|
this.refreshPlayerCurrentOutfit();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.finishButton.on(Phaser.Input.Events.POINTER_UP, () => {
|
||||||
|
this.nextSceneToCamera();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const bodyPart in CustomWokaBodyPart) {
|
||||||
|
const button = this.bodyPartsButtons[bodyPart as CustomWokaBodyPart];
|
||||||
|
button.on(IconButtonEvent.Clicked, (selected: boolean) => {
|
||||||
|
if (!selected) {
|
||||||
|
this.selectBodyPartType(bodyPart as CustomWokaBodyPart);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bodyPartsDraggableGrid.on(DraggableGridEvent.ItemClicked, (item: WokaBodyPartSlot) => {
|
||||||
|
void this.bodyPartsDraggableGrid.centerOnItem(this.bodyPartsDraggableGrid.getAllItems().indexOf(item), 500);
|
||||||
|
this.deselectAllSlots();
|
||||||
|
item.select(true);
|
||||||
|
this.setNewBodyPart(Number(item.getId()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
duration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomizeOutfit(): void {
|
||||||
|
for (let i = 0; i < 6; i += 1) {
|
||||||
|
this.selectedLayers[i] = Math.floor(Math.random() * this.layers[i].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeOutfitPart(index: number): void {
|
||||||
|
if (this.selectedBodyPartType === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedLayers[CustomWokaBodyPartOrder[this.selectedBodyPartType]] = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private populateGrid(): void {
|
||||||
|
if (this.selectedBodyPartType === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bodyPartsLayer = this.layers[CustomWokaBodyPartOrder[this.selectedBodyPartType]];
|
||||||
|
|
||||||
|
this.clearGrid();
|
||||||
|
for (let i = 0; i < bodyPartsLayer.length; i += 1) {
|
||||||
|
const slot = new WokaBodyPartSlot(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
...this.getWokaBodyPartSlotConfig(this.selectedBodyPartType, bodyPartsLayer[i].id),
|
||||||
|
offsetX: 0,
|
||||||
|
offsetY: 0,
|
||||||
|
},
|
||||||
|
i
|
||||||
|
).setDisplaySize(this.SLOT_DIMENSION, this.SLOT_DIMENSION);
|
||||||
|
this.bodyPartsDraggableGrid.addItem(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearGrid(): void {
|
||||||
|
this.bodyPartsDraggableGrid.clearAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private deselectAllButtons(): void {
|
||||||
|
for (const bodyPart in CustomWokaBodyPart) {
|
||||||
|
this.bodyPartsButtons[bodyPart as CustomWokaBodyPart].select(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private deselectAllSlots(): void {
|
||||||
|
this.bodyPartsDraggableGrid.getAllItems().forEach((slot) => (slot as WokaBodyPartSlot).select(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { Scene } from "phaser";
|
import { Scene } from "phaser";
|
||||||
import { ErrorScene, ErrorSceneName } from "../Reconnecting/ErrorScene";
|
import { ErrorScene } from "../Reconnecting/ErrorScene";
|
||||||
import { WAError } from "../Reconnecting/WAError";
|
import { WAError } from "../Reconnecting/WAError";
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
import { ReconnectingTextures } from "../Reconnecting/ReconnectingScene";
|
||||||
|
@ -145,7 +145,6 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||||||
createCurrentPlayer(): void {
|
createCurrentPlayer(): void {
|
||||||
for (let i = 0; i < this.playerModels.length; i++) {
|
for (let i = 0; i < this.playerModels.length; i++) {
|
||||||
const playerResource = this.playerModels[i];
|
const playerResource = this.playerModels[i];
|
||||||
|
|
||||||
//check already exist texture
|
//check already exist texture
|
||||||
if (this.players.find((c) => c.texture.key === playerResource.id)) {
|
if (this.players.find((c) => c.texture.key === playerResource.id)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -8,3 +8,72 @@ export enum PlayerAnimationTypes {
|
|||||||
Walk = "walk",
|
Walk = "walk",
|
||||||
Idle = "idle",
|
Idle = "idle",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AnimationData {
|
||||||
|
key: string;
|
||||||
|
frameRate: number;
|
||||||
|
repeat: number;
|
||||||
|
frameModel: string; //todo use an enum
|
||||||
|
frames: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlayerAnimations(name: string): AnimationData[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [0, 1, 2, 1],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [3, 4, 5, 4],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [6, 7, 8, 7],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [9, 10, 11, 10],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [1],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [4],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [7],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`,
|
||||||
|
frameModel: name,
|
||||||
|
frames: [10],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
@ -128,6 +128,10 @@ export class WaScaleManager {
|
|||||||
this.applyNewSize();
|
this.applyNewSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getActualZoom(): number {
|
||||||
|
return this.actualZoom;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used to scale back the ui components to counter-act the zoom.
|
* This is used to scale back the ui components to counter-act the zoom.
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { derived, writable, Writable } from "svelte/store";
|
import { derived, writable, Writable } from "svelte/store";
|
||||||
|
|
||||||
export const customCharacterSceneVisibleStore = writable(false);
|
|
||||||
|
|
||||||
export const activeRowStore = writable(0);
|
export const activeRowStore = writable(0);
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -77,6 +77,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@geprog/vite-plugin-env-config/-/vite-plugin-env-config-4.0.3.tgz#ca04bd9ad9f55fe568917db79266afe8e766e25e"
|
resolved "https://registry.yarnpkg.com/@geprog/vite-plugin-env-config/-/vite-plugin-env-config-4.0.3.tgz#ca04bd9ad9f55fe568917db79266afe8e766e25e"
|
||||||
integrity sha512-2HDCV+6XXJjSuBAhDWLRr111buMQ3bIZrKo3dymIhEJ4oJCC/3yDqg7HDQIn8Y8KKbsM0AtuHMZW4yz2tPBsYg==
|
integrity sha512-2HDCV+6XXJjSuBAhDWLRr111buMQ3bIZrKo3dymIhEJ4oJCC/3yDqg7HDQIn8Y8KKbsM0AtuHMZW4yz2tPBsYg==
|
||||||
|
|
||||||
|
"@home-based-studio/phaser3-utils@^0.4.2":
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@home-based-studio/phaser3-utils/-/phaser3-utils-0.4.2.tgz#b2c1815a6b51321ea8dab027b5badcf714d99fd6"
|
||||||
|
integrity sha512-S0VkAq3z0Kf0vEUUyCDes911icvc+nkUq7lGp23zD/5lk7LTGM51NswSAfel7Rm/DLY8IBxvDTBJADTf/De82w==
|
||||||
|
dependencies:
|
||||||
|
phaser "3.55.1"
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.9.2":
|
"@humanwhocodes/config-array@^0.9.2":
|
||||||
version "0.9.2"
|
version "0.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914"
|
||||||
@ -2161,10 +2168,10 @@ phaser3-rex-plugins@^1.1.42:
|
|||||||
papaparse "^5.3.0"
|
papaparse "^5.3.0"
|
||||||
webfontloader "^1.6.28"
|
webfontloader "^1.6.28"
|
||||||
|
|
||||||
phaser@^3.54.0:
|
phaser@3.55.1:
|
||||||
version "3.54.0"
|
version "3.55.1"
|
||||||
resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.54.0.tgz#46b191e46059aab2a9a57f78525c60b595767eee"
|
resolved "https://registry.yarnpkg.com/phaser/-/phaser-3.55.1.tgz#25923fe845f6598aec57cfb37a5641834e9943a7"
|
||||||
integrity sha512-/1XVI6J2siS0OGwJez7vLbRjars1zb//EvJdYMVyd3wNTUf5DHrvYUj1f6TsEISr4vjnbrNtS66QIuPbGU8x6A==
|
integrity sha512-A5J9/diRz05qc498UNJAaXp85JVkBAEMqxP8pmcRMu1RCLBs4Kx7axd7YxNbXnQuK58JBhTRucngLt8LSpsUlQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3 "^4.0.7"
|
eventemitter3 "^4.0.7"
|
||||||
path "^0.12.7"
|
path "^0.12.7"
|
||||||
|
48
pusher/src/Enum/PlayerTextures.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import * as tg from "generic-type-guard";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
//The list of all the player textures, both the default models and the partial textures used for customization
|
||||||
|
|
||||||
|
const wokaTexture = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
url: z.string(),
|
||||||
|
tags: z.array(z.string()).optional(),
|
||||||
|
tintable: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type WokaTexture = z.infer<typeof wokaTexture>;
|
||||||
|
|
||||||
|
const wokaTextureCollection = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
textures: z.array(wokaTexture),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type WokaTextureCollection = z.infer<typeof wokaTextureCollection>;
|
||||||
|
|
||||||
|
const wokaPartType = z.object({
|
||||||
|
collections: z.array(wokaTextureCollection),
|
||||||
|
required: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type WokaPartType = z.infer<typeof wokaPartType>;
|
||||||
|
|
||||||
|
export const wokaList = z.record(wokaPartType);
|
||||||
|
|
||||||
|
export type WokaList = z.infer<typeof wokaList>;
|
||||||
|
|
||||||
|
export const wokaPartNames = ["woka", "body", "eyes", "hair", "clothes", "hat", "accessory"];
|
||||||
|
|
||||||
|
export const isWokaDetail = new tg.IsInterface()
|
||||||
|
.withProperties({
|
||||||
|
id: tg.isString,
|
||||||
|
})
|
||||||
|
.withOptionalProperties({
|
||||||
|
url: tg.isString,
|
||||||
|
layer: tg.isString,
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
export type WokaDetail = tg.GuardedType<typeof isWokaDetail>;
|
||||||
|
|
||||||
|
export type WokaDetailsResult = WokaDetail[];
|