From bb3b58d8bf1d4b775dc2bb5648e1392178536ee6 Mon Sep 17 00:00:00 2001 From: _Bastler <_Bastler@bstly.de> Date: Fri, 10 Sep 2021 17:06:46 +0200 Subject: [PATCH] Twemoji Svelte --- front/src/Components/App.svelte | 4 ++ .../src/Components/EmoteMenu/EmoteMenu.svelte | 65 +++++++++++++++++ front/src/Phaser/Components/EmoteMenu.ts | 68 ------------------ front/src/Phaser/Entity/Character.ts | 70 +++++++++---------- front/src/Phaser/Game/GameScene.ts | 63 ++++++++++------- front/src/Phaser/Player/Player.ts | 56 +++------------ front/src/Stores/EmoteStore.ts | 4 ++ 7 files changed, 156 insertions(+), 174 deletions(-) create mode 100644 front/src/Components/EmoteMenu/EmoteMenu.svelte delete mode 100644 front/src/Phaser/Components/EmoteMenu.ts create mode 100644 front/src/Stores/EmoteStore.ts diff --git a/front/src/Components/App.svelte b/front/src/Components/App.svelte index 8b033e5f..66aa2507 100644 --- a/front/src/Components/App.svelte +++ b/front/src/Components/App.svelte @@ -26,6 +26,7 @@ import {soundPlayingStore} from "../Stores/SoundPlayingStore"; import ErrorDialog from "./UI/ErrorDialog.svelte"; import Menu from "./Menu/Menu.svelte"; + import EmoteMenu from "./EmoteMenu/EmoteMenu.svelte"; import VideoOverlay from "./Video/VideoOverlay.svelte"; import {gameOverlayVisibilityStore} from "../Stores/GameOverlayStoreVisibility"; import AdminMessage from "./TypeMessage/BanMessage.svelte"; @@ -111,6 +112,9 @@ {/if} + {#if $gameOverlayVisibilityStore} + + {/if} {#if $gameOverlayVisibilityStore}
diff --git a/front/src/Components/EmoteMenu/EmoteMenu.svelte b/front/src/Components/EmoteMenu/EmoteMenu.svelte new file mode 100644 index 00000000..1a1de281 --- /dev/null +++ b/front/src/Components/EmoteMenu/EmoteMenu.svelte @@ -0,0 +1,65 @@ + + +
+
+
+ + \ No newline at end of file diff --git a/front/src/Phaser/Components/EmoteMenu.ts b/front/src/Phaser/Components/EmoteMenu.ts deleted file mode 100644 index 93df2680..00000000 --- a/front/src/Phaser/Components/EmoteMenu.ts +++ /dev/null @@ -1,68 +0,0 @@ -import DOMElement = Phaser.GameObjects.DOMElement; -import { DEPTH_UI_INDEX } from "../Game/DepthIndexes"; -import { waScaleManager } from "../Services/WaScaleManager"; -import type { UserInputManager } from "../UserInput/UserInputManager"; -import { EmojiButton } from '@joeattardi/emoji-button'; -import { HtmlUtils } from "../../WebRtc/HtmlUtils"; - -export const EmoteMenuClickEvent = "emoteClick"; - -export class EmoteMenu extends Phaser.GameObjects.Container { - private resizeCallback: OmitThisParameter<() => void>; - private container: DOMElement; - private picker: EmojiButton; - - constructor(scene: Phaser.Scene, x: number, y: number, private userInputManager: UserInputManager) { - super(scene, x, y); - this.setDepth(DEPTH_UI_INDEX); - this.scene.add.existing(this); - this.container = new DOMElement(this.scene, 0, 0, "div", "", ""); - this.container.setClassName("emoji-container"); - const scalingFactor = waScaleManager.uiScalingFactor * 0.5; - this.container.setScale(scalingFactor); - this.add(this.container); - const emojiContainer = HtmlUtils.querySelectorOrFail(".emoji-container"); - - this.picker = new EmojiButton({ - rootElement: emojiContainer, - styleProperties: { - '--font': 'Press Start 2P' - } - }); - - this.picker.on("emoji", (selection) => { - this.emit(EmoteMenuClickEvent, selection.emoji); - }); - - this.picker.on("hidden", () => { - this.userInputManager.restoreControls(); - }); - - this.resize(); - this.resizeCallback = this.resize.bind(this); - this.scene.scale.on(Phaser.Scale.Events.RESIZE, this.resizeCallback); - } - - public isOpen(): boolean { - return this.picker.isPickerVisible(); - } - - public openPicker() { - this.userInputManager.disableControls(); - const emojiContainer = HtmlUtils.querySelectorOrFail(".emoji-container"); - this.picker.showPicker(emojiContainer); - } - - public closePicker() { - this.picker.hidePicker(); - } - - private resize() { - this.setScale(waScaleManager.uiScalingFactor); - } - - public destroy() { - this.scene.scale.removeListener(Phaser.Scale.Events.RESIZE, this.resizeCallback); - super.destroy(); - } -} diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index c189b80a..2dfc3c90 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -291,48 +291,48 @@ export abstract class Character extends Container { playEmote(emote: string) { this.cancelPreviousEmote(); - - const scalingFactor = waScaleManager.uiScalingFactor; - const emoteY = -60; - + const emoteY = -45; this.playerName.setVisible(false); - this.emote = new Text(this.scene, -12, 0, emote, { fontFamily: '"twemoji"', fontSize: '24px' }); + this.emote = new Text(this.scene, -10, 0, emote, { fontFamily: '"twemoji"', fontSize: '20px' }); this.emote.setAlpha(0); this.add(this.emote); - this.createStartTransition(scalingFactor, emoteY); + this.createStartTransition(emoteY); } - private createStartTransition(scalingFactor: number, emoteY: number) { - this.emoteTween = this.scene?.tweens.add({ - targets: this.emote, - props: { - scale: scalingFactor, - alpha: 1, - y: emoteY, - }, - ease: "Power2", - duration: 500, - onComplete: () => { - this.startPulseTransition(emoteY, scalingFactor); - }, - }); + private createStartTransition(emoteY: number) { + if (this.emote) { + this.emoteTween = this.scene?.tweens.add({ + targets: this.emote, + props: { + alpha: 1, + y: emoteY, + }, + ease: "Power2", + duration: 500, + onComplete: () => { + this.startPulseTransition(emoteY); + }, + }); + } } - private startPulseTransition(emoteY: number, scalingFactor: number) { - this.emoteTween = this.scene?.tweens.add({ - targets: this.emote, - props: { - y: emoteY * 1.3, - scale: scalingFactor * 1.1, - }, - duration: 250, - yoyo: true, - repeat: 1, - completeDelay: 200, - onComplete: () => { - this.startExitTransition(emoteY); - }, - }); + private startPulseTransition(emoteY: number) { + if (this.emote) { + this.emoteTween = this.scene?.tweens.add({ + targets: this.emote, + props: { + y: emoteY * 1.3, + scale: this.emote.scale * 1.1, + }, + duration: 250, + yoyo: true, + repeat: 1, + completeDelay: 200, + onComplete: () => { + this.startExitTransition(emoteY); + }, + }); + } } private startExitTransition(emoteY: number) { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7c6475e9..dfa0c30d 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -82,6 +82,7 @@ import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStor import { SharedVariablesManager } from "./SharedVariablesManager"; import { playersStore } from "../../Stores/PlayersStore"; import { chatVisibilityStore } from "../../Stores/ChatStore"; +import { emoteStore } from "../../Stores/EmoteStore"; import { audioManagerFileStore, audioManagerVisibilityStore, @@ -94,6 +95,7 @@ import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager"; import { GameMapPropertiesListener } from "./GameMapPropertiesListener"; import type { RadialMenuItem } from "../Components/RadialMenu"; +import { get } from "svelte/store"; export interface GameSceneInitInterface { initPosition: PointInterface | null; @@ -171,6 +173,7 @@ export class GameScene extends DirtyScene { private iframeSubscriptionList!: Array; private peerStoreUnsubscribe!: () => void; private chatVisibilityUnsubscribe!: () => void; + private emoteUnsubscribe!: () => void; private biggestAvailableAreaStoreUnsubscribe!: () => void; MapUrlFile: string; roomUrl: string; @@ -272,7 +275,7 @@ export class GameScene extends DirtyScene { // So if we are in https, we can still try to load a HTTP local resource (can be useful for testing purposes) // See https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure const url = new URL(file.src); - const host = url.host.split(":")[0]; + const host = url.host.split(":")[ 0 ]; if ( window.location.protocol === "https:" && file.src === this.MapUrlFile && @@ -321,8 +324,8 @@ export class GameScene extends DirtyScene { //eslint-disable-next-line @typescript-eslint/no-explicit-any (this.load as any).rexWebFont({ custom: { - families: ["Press Start 2P"], - urls: ["/resources/fonts/fonts.css"], + families: [ "Press Start 2P" ], + urls: [ "/resources/fonts/fonts.css" ], testString: "abcdefg", }, }); @@ -368,7 +371,7 @@ export class GameScene extends DirtyScene { } } - for (const [itemType, objectsOfType] of this.objectsByType) { + for (const [ itemType, objectsOfType ] of this.objectsByType) { // FIXME: we would ideally need for the loader to WAIT for the import to be performed, which means writing our own loader plugin. let itemFactory: ItemFactoryInterface; @@ -399,7 +402,7 @@ export class GameScene extends DirtyScene { // TODO: we should pass here a factory to create sprites (maybe?) // Do we have a state for this object? - const state = roomJoinedAnswer.items[object.id]; + const state = roomJoinedAnswer.items[ object.id ]; const actionableItem = itemFactory.factory(this, object, state); this.actionableItems.set(actionableItem.getId(), actionableItem); @@ -614,7 +617,16 @@ export class GameScene extends DirtyScene { this.openChatIcon.setVisible(!v); }); - Promise.all([this.connectionAnswerPromise as Promise, ...scriptPromises]).then(() => { + this.emoteUnsubscribe = emoteStore.subscribe(() => { + const emoteKey = get(emoteStore); + if (emoteKey) { + this.CurrentPlayer?.playEmote(emoteKey) + this.connection?.emitEmoteEvent(emoteKey); + emoteStore.set(null); + } + }); + + Promise.all([ this.connectionAnswerPromise as Promise, ...scriptPromises ]).then(() => { this.scene.wake(); }); } @@ -702,8 +714,8 @@ export class GameScene extends DirtyScene { if (item === undefined) { console.warn( 'Received an event about object "' + - message.itemId + - '" but cannot find this item on the map.' + message.itemId + + '" but cannot find this item on the map.' ); return; } @@ -897,15 +909,15 @@ export class GameScene extends DirtyScene { } else { console.error( "Error while opening a popup. Cannot find an object on the map with name '" + - openPopupEvent.targetObject + - "'. The first parameter of WA.openPopup() must be the name of a rectangle object in your map." + openPopupEvent.targetObject + + "'. The first parameter of WA.openPopup() must be the name of a rectangle object in your map." ); return; } const escapedMessage = HtmlUtils.escapeHtml(openPopupEvent.message); let html = `