From 4f0bb95a384e0ee9fefc88403be2dc07149795e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gr=C3=A9goire=20parant?= Date: Sun, 5 Sep 2021 18:36:22 +0200 Subject: [PATCH] Emote silent zone (#1342) * Add an emote when the user is in silent zone * Update silent icon strategy * Update strategy for silent zone - Add svelte store - Show silent zone indication and replace camera This update permit to hide silent zone when user is in Jitsi discussion * Fix css silent zone Signed-off-by: Gregoire Parant --- front/src/Components/CameraControls.svelte | 21 +- front/src/Components/MyCamera.svelte | 15 +- front/src/Phaser/Entity/Character.ts | 254 ++++++++++++--------- front/src/Phaser/Game/EmoteManager.ts | 51 +++-- front/src/Phaser/Game/GameScene.ts | 3 + front/src/Phaser/Player/Player.ts | 41 ++-- front/src/Stores/MediaStore.ts | 5 + front/style/style.scss | 16 ++ 8 files changed, 241 insertions(+), 165 deletions(-) diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte index d6b31af4..6dc2726a 100644 --- a/front/src/Components/CameraControls.svelte +++ b/front/src/Components/CameraControls.svelte @@ -1,6 +1,6 @@
@@ -55,22 +62,22 @@ Switch to presentation mode {/if}
-
- {#if $requestedScreenSharingState} +
+ {#if $requestedScreenSharingState && !isSilent} Start screen sharing {:else} Stop screen sharing {/if}
-
- {#if $requestedCameraState} +
+ {#if $requestedCameraState && !isSilent} Turn on webcam {:else} Turn off webcam {/if}
-
- {#if $requestedMicrophoneState} +
+ {#if $requestedMicrophoneState && !isSilent} Turn on microphone {:else} Turn off microphone diff --git a/front/src/Components/MyCamera.svelte b/front/src/Components/MyCamera.svelte index 836a9108..67826859 100644 --- a/front/src/Components/MyCamera.svelte +++ b/front/src/Components/MyCamera.svelte @@ -1,6 +1,6 @@
-
+
{#if $localStreamStore.type === "success" && $localStreamStore.stream} {/if}
+
+ Silent zone +
diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 7263a584..3f85d6e5 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -1,29 +1,30 @@ -import {PlayerAnimationDirections, PlayerAnimationTypes} from "../Player/Animation"; -import {SpeechBubble} from "./SpeechBubble"; +import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation"; +import { SpeechBubble } from "./SpeechBubble"; import Text = Phaser.GameObjects.Text; import Container = Phaser.GameObjects.Container; import Sprite = Phaser.GameObjects.Sprite; -import {TextureError} from "../../Exception/TextureError"; -import {Companion} from "../Companion/Companion"; -import type {GameScene} from "../Game/GameScene"; -import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes"; -import {waScaleManager} from "../Services/WaScaleManager"; +import { TextureError } from "../../Exception/TextureError"; +import { Companion } from "../Companion/Companion"; +import type { GameScene } from "../Game/GameScene"; +import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes"; +import { waScaleManager } from "../Services/WaScaleManager"; import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js"; +import { isSilentStore } from "../../Stores/MediaStore"; -const playerNameY = - 25; +const playerNameY = -25; interface AnimationData { key: string; frameRate: number; repeat: number; frameModel: string; //todo use an enum - frames : number[] + frames: number[]; } const interactiveRadius = 35; export abstract class Character extends Container { - private bubble: SpeechBubble|null = null; + private bubble: SpeechBubble | null = null; private readonly playerName: Text; public PlayerValue: string; public sprites: Map; @@ -32,35 +33,41 @@ export abstract class Character extends Container { private invisible: boolean; public companion?: Companion; private emote: Phaser.GameObjects.Sprite | null = null; - private emoteTween: Phaser.Tweens.Tween|null = null; + private emoteTween: Phaser.Tweens.Tween | null = null; scene: GameScene; - constructor(scene: GameScene, - x: number, - y: number, - texturesPromise: Promise, - name: string, - direction: PlayerAnimationDirections, - moving: boolean, - frame: string | number, - isClickable: boolean, - companion: string|null, - companionTexturePromise?: Promise + constructor( + scene: GameScene, + x: number, + y: number, + texturesPromise: Promise, + name: string, + direction: PlayerAnimationDirections, + moving: boolean, + frame: string | number, + isClickable: boolean, + companion: string | null, + companionTexturePromise?: Promise ) { - super(scene, x, y/*, texture, frame*/); + super(scene, x, y /*, texture, frame*/); this.scene = scene; this.PlayerValue = name; - this.invisible = true + this.invisible = true; this.sprites = new Map(); //textures are inside a Promise in case they need to be lazyloaded before use. texturesPromise.then((textures) => { this.addTextures(textures, frame); - this.invisible = false - }) + this.invisible = false; + }); - this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "gray"}); + this.playerName = new Text(scene, 0, playerNameY, name, { + fontFamily: '"Press Start 2P"', + fontSize: "8px", + strokeThickness: 2, + stroke: "gray", + }); this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX); this.add(this.playerName); @@ -71,18 +78,17 @@ export abstract class Character extends Container { useHandCursor: true, }); - this.on('pointerover',() => { + this.on("pointerover", () => { this.getOutlinePlugin()?.add(this.playerName, { thickness: 2, - outlineColor: 0xffff00 + outlineColor: 0xffff00, }); this.scene.markDirty(); }); - this.on('pointerout',() => { + this.on("pointerout", () => { this.getOutlinePlugin()?.remove(this.playerName); this.scene.markDirty(); - }) - + }); } scene.add.existing(this); @@ -97,38 +103,38 @@ export abstract class Character extends Container { this.playAnimation(direction, moving); - if (typeof companion === 'string') { + if (typeof companion === "string") { this.addCompanion(companion, companionTexturePromise); } } - private getOutlinePlugin(): OutlinePipelinePlugin|undefined { - return this.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined; + private getOutlinePlugin(): OutlinePipelinePlugin | undefined { + return this.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined; } public addCompanion(name: string, texturePromise?: Promise): void { - if (typeof texturePromise !== 'undefined') { + if (typeof texturePromise !== "undefined") { this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise); } } public addTextures(textures: string[], frame?: string | number): void { for (const texture of textures) { - if(this.scene && !this.scene.textures.exists(texture)){ - throw new TextureError('texture not found'); + if (this.scene && !this.scene.textures.exists(texture)) { + throw new TextureError("texture not found"); } const sprite = new Sprite(this.scene, 0, 0, texture, frame); this.add(sprite); - this.getPlayerAnimations(texture).forEach(d => { + this.getPlayerAnimations(texture).forEach((d) => { this.scene.anims.create({ key: d.key, - frames: this.scene.anims.generateFrameNumbers(d.frameModel, {frames: d.frames}), + frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }), frameRate: d.frameRate, - repeat: d.repeat + repeat: d.repeat, }); - }) + }); // Needed, otherwise, animations are not handled correctly. - if(this.scene) { + if (this.scene) { this.scene.sys.updateList.add(sprite); } this.sprites.set(texture, sprite); @@ -136,68 +142,77 @@ export abstract class Character extends Container { } 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 - }]; + 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; for (const [texture, sprite] of this.sprites.entries()) { if (!sprite.anims) { - console.error('ANIMS IS NOT DEFINED!!!'); + console.error("ANIMS IS NOT DEFINED!!!"); return; } if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) { - sprite.play(texture+'-'+direction+'-'+PlayerAnimationTypes.Walk, true); + sprite.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Walk, true); } else if (!moving) { - sprite.anims.play(texture + '-' + direction + '-'+PlayerAnimationTypes.Idle, true); + sprite.anims.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Idle, true); } } } @@ -205,7 +220,7 @@ export abstract class Character extends Container { protected getBody(): Phaser.Physics.Arcade.Body { const body = this.body; if (!(body instanceof Phaser.Physics.Arcade.Body)) { - throw new Error('Container does not have arcade body'); + throw new Error("Container does not have arcade body"); } return body; } @@ -216,16 +231,20 @@ export abstract class Character extends Container { body.setVelocity(x, y); // up or down animations are prioritized over left and right - if (body.velocity.y < 0) { //moving up + if (body.velocity.y < 0) { + //moving up this.lastDirection = PlayerAnimationDirections.Up; this.playAnimation(PlayerAnimationDirections.Up, true); - } else if (body.velocity.y > 0) { //moving down + } else if (body.velocity.y > 0) { + //moving down this.lastDirection = PlayerAnimationDirections.Down; this.playAnimation(PlayerAnimationDirections.Down, true); - } else if (body.velocity.x > 0) { //moving right + } else if (body.velocity.x > 0) { + //moving right this.lastDirection = PlayerAnimationDirections.Right; this.playAnimation(PlayerAnimationDirections.Right, true); - } else if (body.velocity.x < 0) { //moving left + } else if (body.velocity.x < 0) { + //moving left this.lastDirection = PlayerAnimationDirections.Left; this.playAnimation(PlayerAnimationDirections.Left, true); } @@ -237,32 +256,39 @@ export abstract class Character extends Container { } } - stop(){ + stop() { this.getBody().setVelocity(0, 0); this.playAnimation(this.lastDirection, false); } say(text: string) { if (this.bubble) return; - this.bubble = new SpeechBubble(this.scene, this, text) + this.bubble = new SpeechBubble(this.scene, this, text); setTimeout(() => { if (this.bubble !== null) { this.bubble.destroy(); this.bubble = null; } - }, 3000) + }, 3000); } destroy(): void { for (const sprite of this.sprites.values()) { - if(this.scene) { + if (this.scene) { this.scene.sys.updateList.remove(sprite); } } - this.list.forEach(objectContaining => objectContaining.destroy()) + this.list.forEach((objectContaining) => objectContaining.destroy()); super.destroy(); } + isSilent() { + isSilentStore.set(true); + } + noSilent() { + isSilentStore.set(false); + } + playEmote(emoteKey: string) { this.cancelPreviousEmote(); @@ -270,7 +296,7 @@ export abstract class Character extends Container { const emoteY = -30 - scalingFactor * 10; this.playerName.setVisible(false); - this.emote = new Sprite(this.scene, 0, 0, emoteKey); + this.emote = new Sprite(this.scene, 0, 0, emoteKey); this.emote.setAlpha(0); this.emote.setScale(0.1 * scalingFactor); this.add(this.emote); @@ -287,11 +313,11 @@ export abstract class Character extends Container { alpha: 1, y: emoteY, }, - ease: 'Power2', + ease: "Power2", duration: 500, onComplete: () => { this.startPulseTransition(emoteY, scalingFactor); - } + }, }); } @@ -300,7 +326,7 @@ export abstract class Character extends Container { targets: this.emote, props: { y: emoteY * 1.3, - scale: scalingFactor * 1.1 + scale: scalingFactor * 1.1, }, duration: 250, yoyo: true, @@ -308,7 +334,7 @@ export abstract class Character extends Container { completeDelay: 200, onComplete: () => { this.startExitTransition(emoteY); - } + }, }); } @@ -319,11 +345,11 @@ export abstract class Character extends Container { alpha: 0, y: 2 * emoteY, }, - ease: 'Power2', + ease: "Power2", duration: 500, onComplete: () => { this.destroyEmote(); - } + }, }); } @@ -331,7 +357,7 @@ export abstract class Character extends Container { if (!this.emote) return; this.emoteTween?.remove(); - this.destroyEmote() + this.destroyEmote(); } private destroyEmote() { diff --git a/front/src/Phaser/Game/EmoteManager.ts b/front/src/Phaser/Game/EmoteManager.ts index 2e0bbd67..7c6acd5b 100644 --- a/front/src/Phaser/Game/EmoteManager.ts +++ b/front/src/Phaser/Game/EmoteManager.ts @@ -1,37 +1,36 @@ -import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures"; -import {emoteEventStream} from "../../Connexion/EmoteEventStream"; -import type {GameScene} from "./GameScene"; -import type {RadialMenuItem} from "../Components/RadialMenu"; +import type { BodyResourceDescriptionInterface } from "../Entity/PlayerTextures"; +import { emoteEventStream } from "../../Connexion/EmoteEventStream"; +import type { GameScene } from "./GameScene"; +import type { RadialMenuItem } from "../Components/RadialMenu"; import LoaderPlugin = Phaser.Loader.LoaderPlugin; -import type {Subscription} from "rxjs"; - +import type { Subscription } from "rxjs"; interface RegisteredEmote extends BodyResourceDescriptionInterface { name: string; img: string; } -export const emotes: {[key: string]: RegisteredEmote} = { - 'emote-heart': {name: 'emote-heart', img: 'resources/emotes/heart-emote.png'}, - 'emote-clap': {name: 'emote-clap', img: 'resources/emotes/clap-emote.png'}, - 'emote-hand': {name: 'emote-hand', img: 'resources/emotes/hand-emote.png'}, - 'emote-thanks': {name: 'emote-thanks', img: 'resources/emotes/thanks-emote.png'}, - 'emote-thumb-up': {name: 'emote-thumb-up', img: 'resources/emotes/thumb-up-emote.png'}, - 'emote-thumb-down': {name: 'emote-thumb-down', img: 'resources/emotes/thumb-down-emote.png'}, +export const emotes: { [key: string]: RegisteredEmote } = { + "emote-heart": { name: "emote-heart", img: "resources/emotes/heart-emote.png" }, + "emote-clap": { name: "emote-clap", img: "resources/emotes/clap-emote.png" }, + "emote-hand": { name: "emote-hand", img: "resources/emotes/hand-emote.png" }, + "emote-thanks": { name: "emote-thanks", img: "resources/emotes/thanks-emote.png" }, + "emote-thumb-up": { name: "emote-thumb-up", img: "resources/emotes/thumb-up-emote.png" }, + "emote-thumb-down": { name: "emote-thumb-down", img: "resources/emotes/thumb-down-emote.png" }, }; export class EmoteManager { private subscription: Subscription; - + constructor(private scene: GameScene) { this.subscription = emoteEventStream.stream.subscribe((event) => { const actor = this.scene.MapPlayersByKey.get(event.userId); if (actor) { - this.lazyLoadEmoteTexture(event.emoteName).then(emoteKey => { + this.lazyLoadEmoteTexture(event.emoteName).then((emoteKey) => { actor.playEmote(emoteKey); - }) + }); } - }) + }); } createLoadingPromise(loadPlugin: LoaderPlugin, playerResourceDescriptor: BodyResourceDescriptionInterface) { return new Promise((res) => { @@ -39,20 +38,22 @@ export class EmoteManager { return res(playerResourceDescriptor.name); } loadPlugin.image(playerResourceDescriptor.name, playerResourceDescriptor.img); - loadPlugin.once('filecomplete-image-' + playerResourceDescriptor.name, () => res(playerResourceDescriptor.name)); + loadPlugin.once("filecomplete-image-" + playerResourceDescriptor.name, () => + res(playerResourceDescriptor.name) + ); }); } - + lazyLoadEmoteTexture(textureKey: string): Promise { const emoteDescriptor = emotes[textureKey]; if (emoteDescriptor === undefined) { - throw 'Emote not found!'; + throw "Emote not found!"; } const loadPromise = this.createLoadingPromise(this.scene.load, emoteDescriptor); this.scene.load.start(); - return loadPromise + return loadPromise; } - + getMenuImages(): Promise { const promises = []; for (const key in emotes) { @@ -60,14 +61,14 @@ export class EmoteManager { return { image: textureKey, name: textureKey, - } + }; }); promises.push(promise); } return Promise.all(promises); } - + destroy() { this.subscription.unsubscribe(); } -} \ No newline at end of file +} diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9fbb7ea3..39c87db7 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -93,6 +93,7 @@ import { userIsAdminStore } from "../../Stores/GameStore"; import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager"; import { GameMapPropertiesListener } from "./GameMapPropertiesListener"; +import type { RadialMenuItem } from "../Components/RadialMenu"; export interface GameSceneInitInterface { initPosition: PointInterface | null; @@ -853,8 +854,10 @@ export class GameScene extends DirtyScene { this.gameMap.onPropertyChange("silent", (newValue, oldValue) => { if (newValue === undefined || newValue === false || newValue === "") { this.connection?.setSilent(false); + this.CurrentPlayer.noSilent(); } else { this.connection?.setSilent(true); + this.CurrentPlayer.isSilent(); } }); this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => { diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index 7ed366f7..c4e68dd3 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -1,9 +1,9 @@ -import {PlayerAnimationDirections} from "./Animation"; -import type {GameScene} from "../Game/GameScene"; -import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager"; -import {Character} from "../Entity/Character"; -import {userMovingStore} from "../../Stores/GameStore"; -import {RadialMenu, RadialMenuClickEvent, RadialMenuItem} from "../Components/RadialMenu"; +import { PlayerAnimationDirections } from "./Animation"; +import type { GameScene } from "../Game/GameScene"; +import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager"; +import { Character } from "../Entity/Character"; +import { userMovingStore } from "../../Stores/GameStore"; +import { RadialMenu, RadialMenuClickEvent, RadialMenuItem } from "../Components/RadialMenu"; export const hasMovedEventName = "hasMoved"; export const requestEmoteEventName = "requestEmote"; @@ -11,7 +11,7 @@ export const requestEmoteEventName = "requestEmote"; export class Player extends Character { private previousDirection: string = PlayerAnimationDirections.Down; private wasMoving: boolean = false; - private emoteMenu: RadialMenu|null = null; + private emoteMenu: RadialMenu | null = null; private updateListener: () => void; constructor( @@ -23,7 +23,7 @@ export class Player extends Character { direction: PlayerAnimationDirections, moving: boolean, private userInputManager: UserInputManager, - companion: string|null, + companion: string | null, companionTexturePromise?: Promise ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise); @@ -37,7 +37,7 @@ export class Player extends Character { this.emoteMenu.y = this.y; } }; - this.scene.events.addListener('postupdate', this.updateListener); + this.scene.events.addListener("postupdate", this.updateListener); } moveUser(delta: number): void { @@ -73,14 +73,14 @@ export class Player extends Character { if (x !== 0 || y !== 0) { this.move(x, y); - this.emit(hasMovedEventName, {moving, direction, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction, x: this.x, y: this.y }); } else if (this.wasMoving && moving) { // slow joystick movement this.move(0, 0); - this.emit(hasMovedEventName, {moving, direction: this.previousDirection, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y }); } else if (this.wasMoving && !moving) { this.stop(); - this.emit(hasMovedEventName, {moving, direction: this.previousDirection, x: this.x, y: this.y}); + this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y }); } if (direction !== null) { @@ -94,17 +94,17 @@ export class Player extends Character { return this.wasMoving; } - openOrCloseEmoteMenu(emotes:RadialMenuItem[]) { - if(this.emoteMenu) { + openOrCloseEmoteMenu(emotes: RadialMenuItem[]) { + if (this.emoteMenu) { this.closeEmoteMenu(); } else { this.openEmoteMenu(emotes); } } - openEmoteMenu(emotes:RadialMenuItem[]): void { + openEmoteMenu(emotes: RadialMenuItem[]): void { this.cancelPreviousEmote(); - this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes) + this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes); this.emoteMenu.on(RadialMenuClickEvent, (item: RadialMenuItem) => { this.closeEmoteMenu(); this.emit(requestEmoteEventName, item.name); @@ -112,6 +112,13 @@ export class Player extends Character { }); } + isSilent() { + super.isSilent(); + } + noSilent() { + super.noSilent(); + } + closeEmoteMenu(): void { if (!this.emoteMenu) return; this.emoteMenu.destroy(); @@ -119,7 +126,7 @@ export class Player extends Character { } destroy() { - this.scene.events.removeListener('postupdate', this.updateListener); + this.scene.events.removeListener("postupdate", this.updateListener); super.destroy(); } } diff --git a/front/src/Stores/MediaStore.ts b/front/src/Stores/MediaStore.ts index 48832773..0ab40a79 100644 --- a/front/src/Stores/MediaStore.ts +++ b/front/src/Stores/MediaStore.ts @@ -569,3 +569,8 @@ localStreamStore.subscribe((streamResult) => { * A store containing the real active media is mobile */ export const obtainedMediaConstraintIsMobileStore = writable(false); + +/** + * A store containing if user is silent, so if he is in silent zone. This permit to show et hide camera of user + */ +export const isSilentStore = writable(false); diff --git a/front/style/style.scss b/front/style/style.scss index ecfc92fe..31eddfc8 100644 --- a/front/style/style.scss +++ b/front/style/style.scss @@ -1083,3 +1083,19 @@ div.action.danger p.action-body{ } } } + +div.is-silent { + position: absolute; + bottom: 40px; + border-radius: 15px 15px 15px 15px; + max-height: 20%; + transition: right 350ms; + right: -20vw; + background-color: black; + font-size: 20px; + color: white; + padding: 30px 20px; +} +div.is-silent.hide { + right: 15px; +}