diff --git a/front/dist/resources/fonts/ka1.ttf b/front/dist/resources/fonts/ka1.ttf
new file mode 100644
index 00000000..d1df8523
Binary files /dev/null and b/front/dist/resources/fonts/ka1.ttf differ
diff --git a/front/dist/resources/html/gameMenu.html b/front/dist/resources/html/gameMenu.html
new file mode 100644
index 00000000..a5190062
--- /dev/null
+++ b/front/dist/resources/html/gameMenu.html
@@ -0,0 +1,34 @@
+
+
+
diff --git a/front/dist/resources/html/gameMenuIcon.html b/front/dist/resources/html/gameMenuIcon.html
new file mode 100644
index 00000000..f7f5e9aa
--- /dev/null
+++ b/front/dist/resources/html/gameMenuIcon.html
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/front/dist/resources/html/gameQualityMenu.html b/front/dist/resources/html/gameQualityMenu.html
new file mode 100644
index 00000000..00599386
--- /dev/null
+++ b/front/dist/resources/html/gameQualityMenu.html
@@ -0,0 +1,73 @@
+
+
+
diff --git a/front/dist/resources/objects/talk.png b/front/dist/resources/objects/talk.png
new file mode 100644
index 00000000..b9ecdb30
Binary files /dev/null and b/front/dist/resources/objects/talk.png differ
diff --git a/front/src/Administration/ConsoleGlobalMessageManager.ts b/front/src/Administration/ConsoleGlobalMessageManager.ts
index 03929a46..d437f7c0 100644
--- a/front/src/Administration/ConsoleGlobalMessageManager.ts
+++ b/front/src/Administration/ConsoleGlobalMessageManager.ts
@@ -3,15 +3,12 @@ import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {RoomConnection} from "../Connexion/RoomConnection";
import {PlayGlobalMessageInterface} from "../Connexion/ConnexionModels";
import {ADMIN_URL} from "../Enum/EnvironmentVariable";
-import {mediaManager} from "../WebRtc/MediaManager";
export const CLASS_CONSOLE_MESSAGE = 'main-console';
export const INPUT_CONSOLE_MESSAGE = 'input-send-text';
export const UPLOAD_CONSOLE_MESSAGE = 'input-upload-music';
export const INPUT_TYPE_CONSOLE = 'input-type';
-export const GAME_QUALITY_SELECT = 'select-game-quality';
export const VIDEO_QUALITY_SELECT = 'select-video-quality';
-export const VIDEO_QUALITY_CONSOLE = 'video-quality';
export const AUDIO_TYPE = 'audio';
export const MESSAGE_TYPE = 'message';
@@ -38,6 +35,7 @@ export class ConsoleGlobalMessageManager {
constructor(private Connection: RoomConnection, userInputManager : UserInputManager, private isAdmin: Boolean) {
this.buttonMainConsole = document.createElement('div');
this.buttonMainConsole.classList.add('console');
+ this.buttonMainConsole.hidden = true;
this.divMainConsole = document.createElement('div');
this.divMainConsole.className = CLASS_CONSOLE_MESSAGE;
this.divMessageConsole = document.createElement('div');
@@ -49,6 +47,7 @@ export class ConsoleGlobalMessageManager {
this.buttonAdminMainConsole = document.createElement('img');
this.userInputManager = userInputManager;
this.initialise();
+
}
initialise() {
@@ -118,9 +117,6 @@ export class ConsoleGlobalMessageManager {
}
});
- /*const buttonText = document.createElement('p');
- buttonText.innerText = 'Console';
- this.buttonMainConsole.appendChild(buttonText);*/
this.divMessageConsole.appendChild(typeConsole);
if(this.isAdmin) {
@@ -130,7 +126,6 @@ export class ConsoleGlobalMessageManager {
this.createUploadAudioPart();
}
this.buttonMainConsole.appendChild(this.buttonSettingsMainConsole);
- this.createSettings();
this.divMainConsole.appendChild(this.buttonMainConsole);
this.divMainConsole.appendChild(this.divMessageConsole);
@@ -263,92 +258,6 @@ export class ConsoleGlobalMessageManager {
this.divMessageConsole.appendChild(section);
}
- createSettings(){
- const labelGame = document.createElement('h1');
- labelGame.innerText = "Game quality";
-
- const selectGame = document.createElement('select');
- selectGame.id = VIDEO_QUALITY_SELECT;
-
- const option1 : HTMLOptionElement = document.createElement('option');
- option1.value = '120';
- option1.innerText = 'High video quality (120 fps)';
- selectGame.appendChild(option1);
-
- const option2 : HTMLOptionElement = document.createElement('option');
- option2.value = '60';
- option2.innerText = 'Medium video quality (60 fps, recommended)';
- selectGame.appendChild(option2);
-
- const option3 : HTMLOptionElement = document.createElement('option');
- option3.value = '40';
- option3.innerText = 'Minimum video quality (40 fps)';
- selectGame.appendChild(option3);
-
- const option4 : HTMLOptionElement = document.createElement('option');
- option4.value = '20';
- option4.innerText = 'Small video quality (20 fps)';
- selectGame.appendChild(option4);
-
- const labelVideo = document.createElement('h1');
- labelVideo.innerText = "Video quality";
-
- const selectVideo = document.createElement('select');
- selectVideo.id = GAME_QUALITY_SELECT;
-
- const optionVideo1 : HTMLOptionElement = document.createElement('option');
- optionVideo1.value = '30';
- optionVideo1.innerText = 'High video quality (30 fps)';
- selectVideo.appendChild(optionVideo1);
-
- const optionVideo2 : HTMLOptionElement = document.createElement('option');
- optionVideo2.value = '20';
- optionVideo2.innerText = 'Medium video quality (20 fps, recommended)';
- selectVideo.appendChild(optionVideo2);
-
- const optionVideo3 : HTMLOptionElement = document.createElement('option');
- optionVideo3.value = '10';
- optionVideo3.innerText = 'Minimum video quality (10 fps)';
- selectVideo.appendChild(optionVideo3);
-
- const optionVideo4 : HTMLOptionElement = document.createElement('option');
- optionVideo4.value = '5';
- optionVideo4.innerText = 'Small video quality (5 fps)';
- selectVideo.appendChild(optionVideo4);
-
- selectGame.value = '60';
- const localQualityGame = localStorage.getItem(GAME_QUALITY_SELECT);
- if(localQualityGame){
- selectGame.value = localQualityGame;
- }
-
- selectVideo.value = '30';
- const localQualityCam = localStorage.getItem(VIDEO_QUALITY_SELECT);
- if(localQualityCam){
- selectVideo.value = localQualityCam;
- }
-
- const divButtonAction = document.createElement('div');
- divButtonAction.className = 'btn-action';
- const buttonSave = document.createElement('button');
- buttonSave.innerText = 'Save';
- buttonSave.classList.add('btn');
- buttonSave.addEventListener('click', () => {
- this.saveSetting(selectGame.value, selectVideo.value);
- this.disabledSettingConsole();
- });
- divButtonAction.appendChild(buttonSave);
-
- const section = document.createElement('section');
- section.id = this.getSectionId(VIDEO_QUALITY_CONSOLE);
- section.appendChild(labelGame);
- section.appendChild(selectGame);
- section.appendChild(labelVideo);
- section.appendChild(selectVideo);
- section.appendChild(divButtonAction);
- this.divSettingConsole.appendChild(section);
- }
-
private static loadCss(): Promise {
return new Promise((resolve, reject) => {
if (ConsoleGlobalMessageManager.cssLoaded) {
@@ -421,19 +330,6 @@ export class ConsoleGlobalMessageManager {
this.Connection.emitGlobalMessage(GlobalMessage);
}
- private saveSetting(valueGame: string, valueVideo: string){
- const previousGameValue = localStorage.getItem(GAME_QUALITY_SELECT);
- if(!previousGameValue || previousGameValue !== valueGame) {
- localStorage.setItem(GAME_QUALITY_SELECT, valueGame);
- window.location.reload();
- }
- const previousVideoValue = localStorage.getItem(VIDEO_QUALITY_SELECT);
- if(!previousVideoValue || previousVideoValue !== valueVideo) {
- localStorage.setItem(VIDEO_QUALITY_SELECT, valueVideo);
- mediaManager.updateCameraQuality(parseInt(valueVideo));
- }
- }
-
active(){
this.userInputManager.clearAllInputKeyboard();
this.divMainConsole.style.top = '0';
@@ -453,12 +349,14 @@ export class ConsoleGlobalMessageManager {
}
this.active();
this.divMessageConsole.classList.add('active');
+ this.buttonMainConsole.hidden = false;
this.buttonSendMainConsole.classList.add('active');
}
disabledMessageConsole(){
this.activeMessage = false;
this.disabled();
+ this.buttonMainConsole.hidden = false;
this.divMessageConsole.classList.remove('active');
this.buttonSendMainConsole.classList.remove('active');
}
diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts
index b670a388..a113a00c 100644
--- a/front/src/Connexion/ConnectionManager.ts
+++ b/front/src/Connexion/ConnectionManager.ts
@@ -55,8 +55,7 @@ class ConnectionManager {
} else {
roomId = window.location.pathname + window.location.hash;
}
- const room = new Room(roomId);
- return Promise.resolve(room);
+ return Promise.resolve(new Room(roomId));
}
return Promise.reject('Invalid URL');
diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts
index afe01bcd..8ac8c7b2 100644
--- a/front/src/Connexion/LocalUserStore.ts
+++ b/front/src/Connexion/LocalUserStore.ts
@@ -1,5 +1,9 @@
import {LocalUser} from "./LocalUser";
+const characterLayersKey = 'characterLayers';
+const gameQualityKey = 'gameQuality';
+const videoQualityKey = 'videoQuality';
+
//todo: add localstorage fallback
class LocalUserStore {
@@ -31,6 +35,27 @@ class LocalUserStore {
getCustomCursorPosition(): {activeRow:number, selectedLayers:number[]}|null {
return JSON.parse(window.localStorage.getItem('customCursorPosition') || "null");
}
+
+ setCharacterLayers(layers: string[]): void {
+ window.localStorage.setItem(characterLayersKey, JSON.stringify(layers));
+ }
+ getCharacterLayers(): string[]|null {
+ return JSON.parse(window.localStorage.getItem(characterLayersKey) || "null");
+ }
+
+ getGameQualityValue(): number {
+ return parseInt(window.localStorage.getItem(gameQualityKey) || '') || 60;
+ }
+ setGameQualityValue(value: number): void {
+ localStorage.setItem(gameQualityKey, '' + value);
+ }
+
+ getVideoQualityValue(): number {
+ return parseInt(window.localStorage.getItem(videoQualityKey) || '') || 20;
+ }
+ setVideoQualityValue(value: number): void {
+ localStorage.setItem(videoQualityKey, '' + value);
+ }
}
export const localUserStore = new LocalUserStore();
\ No newline at end of file
diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts
index cc033974..beb7f9dd 100644
--- a/front/src/Connexion/RoomConnection.ts
+++ b/front/src/Connexion/RoomConnection.ts
@@ -583,4 +583,8 @@ export class RoomConnection implements RoomConnection {
public hasTag(tag: string): boolean {
return this.tags.includes(tag);
}
+
+ public isAdmin(): boolean {
+ return this.hasTag('admin');
+ }
}
diff --git a/front/src/Phaser/Components/ChatModeIcon.ts b/front/src/Phaser/Components/ChatModeIcon.ts
new file mode 100644
index 00000000..932a4d88
--- /dev/null
+++ b/front/src/Phaser/Components/ChatModeIcon.ts
@@ -0,0 +1,11 @@
+export class ChatModeIcon extends Phaser.GameObjects.Sprite {
+ constructor(scene: Phaser.Scene, x: number, y: number) {
+ super(scene, x, y, 'layout_modes', 3);
+ scene.add.existing(this);
+ this.setScrollFactor(0, 0);
+ this.setOrigin(0, 1);
+ this.setInteractive();
+ this.setVisible(false);
+ this.setDepth(99999);
+ }
+}
\ No newline at end of file
diff --git a/front/src/Phaser/Components/OpenChatIcon.ts b/front/src/Phaser/Components/OpenChatIcon.ts
new file mode 100644
index 00000000..bf293bab
--- /dev/null
+++ b/front/src/Phaser/Components/OpenChatIcon.ts
@@ -0,0 +1,18 @@
+import {discussionManager} from "../../WebRtc/DiscussionManager";
+
+export const openChatIconName = 'openChatIcon';
+export class OpenChatIcon extends Phaser.GameObjects.Image {
+ constructor(scene: Phaser.Scene, x: number, y: number) {
+ super(scene, x, y, openChatIconName);
+ scene.add.existing(this);
+ this.setScrollFactor(0, 0);
+ this.setOrigin(0, 1);
+ this.displayWidth = 30;
+ this.displayHeight = 30;
+ this.setInteractive();
+ this.setVisible(false)
+ this.setDepth(99999);
+
+ this.on("pointerup", () => discussionManager.showDiscussionPart());
+ }
+}
\ No newline at end of file
diff --git a/front/src/Phaser/Components/PresentationModeIcon.ts b/front/src/Phaser/Components/PresentationModeIcon.ts
new file mode 100644
index 00000000..49ff2ea1
--- /dev/null
+++ b/front/src/Phaser/Components/PresentationModeIcon.ts
@@ -0,0 +1,11 @@
+export class PresentationModeIcon extends Phaser.GameObjects.Sprite {
+ constructor(scene: Phaser.Scene, x: number, y: number) {
+ super(scene, x, y, 'layout_modes', 0);
+ scene.add.existing(this);
+ this.setScrollFactor(0, 0);
+ this.setOrigin(0, 1);
+ this.setInteractive();
+ this.setVisible(false);
+ this.setDepth(99999);
+ }
+}
\ No newline at end of file
diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts
index cc575b6a..88ed1c52 100644
--- a/front/src/Phaser/Game/GameManager.ts
+++ b/front/src/Phaser/Game/GameManager.ts
@@ -1,6 +1,11 @@
import {GameScene} from "./GameScene";
import {connectionManager} from "../../Connexion/ConnectionManager";
import {Room} from "../../Connexion/Room";
+import {MenuSceneName} from "../Menu/MenuScene";
+import {LoginSceneName} from "../Login/LoginScene";
+import {SelectCharacterSceneName} from "../Login/SelectCharacterScene";
+import {EnableCameraSceneName} from "../Login/EnableCameraScene";
+import {localUserStore} from "../../Connexion/LocalUserStore";
export interface HasMovedEvent {
direction: string;
@@ -9,29 +14,48 @@ export interface HasMovedEvent {
y: number;
}
+/**
+ * This class should be responsible for any scene starting/stopping
+ */
export class GameManager {
- private playerName!: string;
- private characterLayers!: string[];
+ private playerName: string|null;
+ private characterLayers: string[]|null;
private startRoom!:Room;
+ currentSceneName: string|null = null;
+
+ constructor() {
+ this.playerName = localUserStore.getName();
+ this.characterLayers = localUserStore.getCharacterLayers();
+ }
- public async init(scenePlugin: Phaser.Scenes.ScenePlugin) {
+ public async init(scenePlugin: Phaser.Scenes.ScenePlugin): Promise {
this.startRoom = await connectionManager.initGameConnexion();
await this.loadMap(this.startRoom, scenePlugin);
+
+ if (!this.playerName) {
+ return LoginSceneName;
+ } else if (!this.characterLayers) {
+ return SelectCharacterSceneName;
+ } else {
+ return EnableCameraSceneName;
+ }
}
public setPlayerName(name: string): void {
this.playerName = name;
+ localUserStore.setName(name);
}
public setCharacterLayers(layers: string[]): void {
this.characterLayers = layers;
+ localUserStore.setCharacterLayers(layers);
}
- getPlayerName(): string {
+ getPlayerName(): string|null {
return this.playerName;
}
- getCharacterSelected(): string[] {
+ getCharacterLayers(): string[]|null {
return this.characterLayers;
}
@@ -48,7 +72,28 @@ export class GameManager {
}
public goToStartingMap(scenePlugin: Phaser.Scenes.ScenePlugin): void {
- scenePlugin.start(this.startRoom.id);
+ console.log('starting '+ (this.currentSceneName || this.startRoom.id))
+ scenePlugin.start(this.currentSceneName || this.startRoom.id);
+ //the menu scene launches faster than the gameScene, so we delay it to not have menu buttons on a black screen
+ setTimeout(() => scenePlugin.launch(MenuSceneName), 1000);
+ }
+
+ /**
+ * Temporary leave a gameScene to go back to the loginScene for example.
+ * This will close the socket connections and stop the gameScene, but won't remove it.
+ */
+ leaveGame(scene: Phaser.Scene, targetSceneName: string): void {
+ if (this.currentSceneName === null) throw 'No current scene id set!';
+ const gameScene: GameScene = scene.scene.get(this.currentSceneName) as GameScene;
+ gameScene.cleanupClosingScene();
+ scene.scene.stop(this.currentSceneName);
+ scene.scene.stop(MenuSceneName);
+ scene.scene.run(targetSceneName);
+ }
+
+ public getCurrentGameScene(scene: Phaser.Scene): GameScene {
+ if (this.currentSceneName === null) throw 'No current scene id set!';
+ return scene.scene.get(this.currentSceneName) as GameScene
}
}
diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts
index d7ca5adc..cbfa64d9 100644
--- a/front/src/Phaser/Game/GameScene.ts
+++ b/front/src/Phaser/Game/GameScene.ts
@@ -1,4 +1,4 @@
-import {GameManager, gameManager, HasMovedEvent} from "./GameManager";
+import {gameManager, HasMovedEvent} from "./GameManager";
import {
GroupCreatedUpdatedMessageInterface,
MessageUserJoined,
@@ -60,6 +60,9 @@ import {ResizableScene} from "../Login/ResizableScene";
import {Room} from "../../Connexion/Room";
import {jitsiFactory} from "../../WebRtc/JitsiFactory";
import {urlManager} from "../../Url/UrlManager";
+import {PresentationModeIcon} from "../Components/PresentationModeIcon";
+import {ChatModeIcon} from "../Components/ChatModeIcon";
+import {OpenChatIcon, openChatIconName} from "../Components/OpenChatIcon";
export interface GameSceneInitInterface {
initPosition: PointInterface|null,
@@ -99,7 +102,6 @@ interface DeleteGroupEventInterface {
const defaultStartLayerName = 'start';
export class GameScene extends ResizableScene implements CenterListener {
- GameManager : GameManager;
Terrains : Array;
CurrentPlayer!: CurrentGamerInterface;
MapPlayers!: Phaser.Physics.Arcade.Group;
@@ -116,11 +118,11 @@ export class GameScene extends ResizableScene implements CenterListener {
pendingEvents: Queue = new Queue();
private initPosition: PositionInterface|null = null;
private playersPositionInterpolator = new PlayersPositionInterpolator();
- private connection!: RoomConnection;
+ public connection!: RoomConnection;
private simplePeer!: SimplePeer;
private GlobalMessageManager!: GlobalMessageManager;
private UserMessageManager!: UserMessageManager;
- private ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
+ public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
private connectionAnswerPromise: Promise;
private connectionAnswerPromiseResolve!: (value?: RoomJoinedMessageInterface | PromiseLike) => void;
// A promise that will resolve when the "create" method is called (signaling loading is ended)
@@ -149,16 +151,18 @@ export class GameScene extends ResizableScene implements CenterListener {
private userInputManager!: UserInputManager;
private isReconnecting: boolean = false;
private startLayerName!: string | null;
+ private openChatIcon!: OpenChatIcon;
+ private playerName!: string;
+ private characterLayers!: string[];
constructor(private room: Room, MapUrlFile: string) {
super({
key: room.id
});
-
- this.GameManager = gameManager;
this.Terrains = [];
this.groups = new Map();
this.instance = room.getInstance();
+
this.MapUrlFile = MapUrlFile;
this.RoomId = room.id;
@@ -173,6 +177,7 @@ export class GameScene extends ResizableScene implements CenterListener {
//hook preload scene
preload(): void {
+ this.load.image(openChatIconName, 'resources/objects/talk.png');
this.load.on(FILE_LOAD_ERROR, (file: {src: string}) => {
this.scene.start(FourOFourSceneName, {
file: file.src
@@ -306,9 +311,22 @@ export class GameScene extends ResizableScene implements CenterListener {
//hook create scene
create(): void {
+ gameManager.currentSceneName = this.scene.key;
urlManager.pushRoomIdToUrl(this.room);
this.startLayerName = urlManager.getStartLayerNameFromUrl();
+ const playerName = gameManager.getPlayerName();
+ if (!playerName) {
+ throw 'playerName is not set';
+ }
+ this.playerName = playerName;
+ const characterLayers = gameManager.getCharacterLayers();
+ if (!characterLayers) {
+ throw 'characterLayers are not set';
+ }
+ this.characterLayers = characterLayers;
+
+
//initalise map
this.Map = this.add.tilemap(this.MapUrlFile);
this.gameMap = new GameMap(this.mapFile);
@@ -415,23 +433,14 @@ export class GameScene extends ResizableScene implements CenterListener {
this.outlinedItem?.activate();
});
- this.presentationModeSprite = this.add.sprite(2, this.game.renderer.height - 2, 'layout_modes', 0);
- this.presentationModeSprite.setScrollFactor(0, 0);
- this.presentationModeSprite.setOrigin(0, 1);
- this.presentationModeSprite.setInteractive();
- this.presentationModeSprite.setVisible(false);
- this.presentationModeSprite.setDepth(99999);
+ this.presentationModeSprite = new PresentationModeIcon(this, 36, this.game.renderer.height - 2);
this.presentationModeSprite.on('pointerup', this.switchLayoutMode.bind(this));
- this.chatModeSprite = this.add.sprite(36, this.game.renderer.height - 2, 'layout_modes', 3);
- this.chatModeSprite.setScrollFactor(0, 0);
- this.chatModeSprite.setOrigin(0, 1);
- this.chatModeSprite.setInteractive();
- this.chatModeSprite.setVisible(false);
- this.chatModeSprite.setDepth(99999);
+ this.chatModeSprite = new ChatModeIcon(this, 70, this.game.renderer.height - 2);
this.chatModeSprite.on('pointerup', this.switchLayoutMode.bind(this));
+ this.openChatIcon = new OpenChatIcon(this, 2, this.game.renderer.height - 36)
// FIXME: change this to use the UserInputManager class for input
- this.input.keyboard.on('keyup-' + 'M', () => {
+ this.input.keyboard.on('keyup-M', () => {
this.switchLayoutMode();
});
@@ -445,8 +454,8 @@ export class GameScene extends ResizableScene implements CenterListener {
connectionManager.connectToRoomSocket(
this.RoomId,
- gameManager.getPlayerName(),
- gameManager.getCharacterSelected(),
+ this.playerName,
+ this.characterLayers,
{
x: this.startX,
y: this.startY
@@ -459,10 +468,6 @@ export class GameScene extends ResizableScene implements CenterListener {
}).then((onConnect: OnConnectInterface) => {
this.connection = onConnect.connection;
- //this.connection.emitPlayerDetailsMessage(gameManager.getPlayerName(), gameManager.getCharacterSelected())
- /*this.connection.onStartRoom((roomJoinedMessage: RoomJoinedMessageInterface) => {
-
- });*/
this.connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = {
userId: message.userId,
@@ -493,11 +498,13 @@ export class GameScene extends ResizableScene implements CenterListener {
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
+ this.openChatIcon.setVisible(true);
})
this.connection.onGroupDeleted((groupId: number) => {
try {
this.deleteGroup(groupId);
+ this.openChatIcon.setVisible(false);
} catch (e) {
console.error(e);
}
@@ -541,7 +548,7 @@ export class GameScene extends ResizableScene implements CenterListener {
});
// When connection is performed, let's connect SimplePeer
- this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.GameManager.getPlayerName());
+ this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
this.UserMessageManager = new UserMessageManager(this.connection);
@@ -569,7 +576,7 @@ export class GameScene extends ResizableScene implements CenterListener {
//this.initUsersPosition(roomJoinedMessage.users);
this.connectionAnswerPromiseResolve(onConnect.room);
// Analyze tags to find if we are admin. If yes, show console.
- this.ConsoleGlobalMessageManager = new ConsoleGlobalMessageManager(this.connection, this.userInputManager, this.connection.hasTag('admin'));
+ this.ConsoleGlobalMessageManager = new ConsoleGlobalMessageManager(this.connection, this.userInputManager, this.connection.isAdmin());
this.scene.wake();
@@ -649,9 +656,7 @@ export class GameScene extends ResizableScene implements CenterListener {
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
urlManager.pushStartLayerNameToUrl(hash);
if (roomId !== this.scene.key) {
- // We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
- this.connection.closeConnection();
- this.simplePeer.unregister();
+ this.cleanupClosingScene();
this.scene.stop();
this.scene.remove(this.scene.key);
this.scene.start(roomId);
@@ -663,6 +668,12 @@ export class GameScene extends ResizableScene implements CenterListener {
}
}
+ public cleanupClosingScene(): void {
+ // We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
+ this.connection.closeConnection();
+ this.simplePeer.unregister();
+ }
+
private switchLayoutMode(): void {
//if discussion is activated, this layout cannot be activated
if(mediaManager.activatedDiscussion){
@@ -811,8 +822,8 @@ export class GameScene extends ResizableScene implements CenterListener {
this,
this.startX,
this.startY,
- this.GameManager.getPlayerName(),
- this.GameManager.getCharacterSelected(),
+ this.playerName,
+ this.characterLayers,
PlayerAnimationNames.WalkDown,
false,
this.userInputManager
@@ -1174,7 +1185,7 @@ export class GameScene extends ResizableScene implements CenterListener {
}
public startJitsi(roomName: string, jwt?: string): void {
- jitsiFactory.start(roomName, gameManager.getPlayerName(), jwt);
+ jitsiFactory.start(roomName, this.playerName, jwt);
this.connection.setSilent(true);
mediaManager.hideGameOverlay();
@@ -1209,4 +1220,6 @@ export class GameScene extends ResizableScene implements CenterListener {
});
}))
}
+
+
}
diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts
index 41ec95c9..d9236c06 100644
--- a/front/src/Phaser/Login/CustomizeScene.ts
+++ b/front/src/Phaser/Login/CustomizeScene.ts
@@ -9,6 +9,8 @@ import {gameManager} from "../Game/GameManager";
import {ResizableScene} from "./ResizableScene";
import {localUserStore} from "../../Connexion/LocalUserStore";
import {PlayerResourceDescriptionInterface} from "../Entity/Character";
+import {SelectCharacterSceneName} from "./SelectCharacterScene";
+import {LoginSceneName} from "./LoginScene";
export const CustomizeSceneName = "CustomizeScene";
@@ -120,7 +122,8 @@ export class CustomizeScene extends ResizableScene {
gameManager.setCharacterLayers(layers);
- return this.scene.start(EnableCameraSceneName);
+ this.scene.sleep(CustomizeSceneName)
+ this.scene.run(EnableCameraSceneName);
});
this.input.keyboard.on('keydown-RIGHT', () => this.moveCursorHorizontally(1));
diff --git a/front/src/Phaser/Login/EnableCameraScene.ts b/front/src/Phaser/Login/EnableCameraScene.ts
index 56502704..3cee733e 100644
--- a/front/src/Phaser/Login/EnableCameraScene.ts
+++ b/front/src/Phaser/Login/EnableCameraScene.ts
@@ -263,6 +263,7 @@ export class EnableCameraScene extends Phaser.Scene {
mediaManager.stopCamera();
mediaManager.stopMicrophone();
+ this.scene.sleep(EnableCameraSceneName)
gameManager.goToStartingMap(this.scene);
}
diff --git a/front/src/Phaser/Login/EntryScene.ts b/front/src/Phaser/Login/EntryScene.ts
index 6a91be1f..c7527349 100644
--- a/front/src/Phaser/Login/EntryScene.ts
+++ b/front/src/Phaser/Login/EntryScene.ts
@@ -1,13 +1,4 @@
import {gameManager} from "../Game/GameManager";
-import {TextField} from "../Components/TextField";
-import {TextInput} from "../Components/TextInput";
-import {ClickButton} from "../Components/ClickButton";
-import Image = Phaser.GameObjects.Image;
-import Rectangle = Phaser.GameObjects.Rectangle;
-import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "../Entity/Character";
-import {cypressAsserter} from "../../Cypress/CypressAsserter";
-import {SelectCharacterSceneName} from "./SelectCharacterScene";
-import {ResizableScene} from "./ResizableScene";
import {Scene} from "phaser";
import {LoginSceneName} from "./LoginScene";
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
@@ -25,12 +16,9 @@ export class EntryScene extends Scene {
});
}
- preload() {
- }
-
create() {
- gameManager.init(this.scene).then(() => {
- this.scene.start(LoginSceneName);
+ gameManager.init(this.scene).then((nextSceneName) => {
+ this.scene.start(nextSceneName);
}).catch((err) => {
console.error(err)
this.scene.start(FourOFourSceneName, {
diff --git a/front/src/Phaser/Login/LoginScene.ts b/front/src/Phaser/Login/LoginScene.ts
index 2c5c1882..e828f8cb 100644
--- a/front/src/Phaser/Login/LoginScene.ts
+++ b/front/src/Phaser/Login/LoginScene.ts
@@ -1,14 +1,11 @@
import {gameManager} from "../Game/GameManager";
import {TextField} from "../Components/TextField";
import {TextInput} from "../Components/TextInput";
-import {ClickButton} from "../Components/ClickButton";
import Image = Phaser.GameObjects.Image;
-import Rectangle = Phaser.GameObjects.Rectangle;
import {PLAYER_RESOURCES, PlayerResourceDescriptionInterface} from "../Entity/Character";
import {cypressAsserter} from "../../Cypress/CypressAsserter";
import {SelectCharacterSceneName} from "./SelectCharacterScene";
import {ResizableScene} from "./ResizableScene";
-import {localUserStore} from "../../Connexion/LocalUserStore";
//todo: put this constants in a dedicated file
export const LoginSceneName = "LoginScene";
@@ -29,7 +26,7 @@ export class LoginScene extends ResizableScene {
super({
key: LoginSceneName
});
- this.name = localUserStore.getName();
+ this.name = gameManager.getPlayerName() || '';
}
preload() {
@@ -55,7 +52,6 @@ export class LoginScene extends ResizableScene {
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Enter your name:');
this.nameInput = new TextInput(this, this.game.renderer.width / 2, 70, 8, this.name,(text: string) => {
this.name = text;
- localUserStore.setName(text);
});
this.pressReturnField = new TextField(this, this.game.renderer.width / 2, 130, 'Press enter to start');
@@ -87,7 +83,8 @@ export class LoginScene extends ResizableScene {
private login(name: string): void {
gameManager.setPlayerName(name);
- this.scene.start(SelectCharacterSceneName);
+ this.scene.sleep(LoginSceneName)
+ this.scene.run(SelectCharacterSceneName);
}
public onResize(ev: UIEvent): void {
diff --git a/front/src/Phaser/Login/SelectCharacterScene.ts b/front/src/Phaser/Login/SelectCharacterScene.ts
index 25332b7d..5b4dc6cf 100644
--- a/front/src/Phaser/Login/SelectCharacterScene.ts
+++ b/front/src/Phaser/Login/SelectCharacterScene.ts
@@ -116,11 +116,12 @@ export class SelectCharacterScene extends ResizableScene {
}
private nextScene(): void {
+ this.scene.sleep(SelectCharacterSceneName);
if (this.selectedPlayer !== null) {
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
- this.scene.start(EnableCameraSceneName);
+ this.scene.run(EnableCameraSceneName);
} else {
- this.scene.start(CustomizeSceneName);
+ this.scene.run(CustomizeSceneName);
}
}
diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts
new file mode 100644
index 00000000..5d796d00
--- /dev/null
+++ b/front/src/Phaser/Menu/MenuScene.ts
@@ -0,0 +1,189 @@
+import {LoginSceneName} from "../Login/LoginScene";
+import {SelectCharacterSceneName} from "../Login/SelectCharacterScene";
+import {gameManager} from "../Game/GameManager";
+import {localUserStore} from "../../Connexion/LocalUserStore";
+import {mediaManager} from "../../WebRtc/MediaManager";
+
+export const MenuSceneName = 'MenuScene';
+const gameMenuKey = 'gameMenu';
+const gameMenuIconKey = 'gameMenuIcon';
+const gameSettingsMenuKey = 'gameSettingsMenu';
+
+const closedSideMenuX = -200;
+const openedSideMenuX = 0;
+
+/**
+ * The scene that manages the game menu, rendered using a DOM element.
+ */
+export class MenuScene extends Phaser.Scene {
+ private menuElement!: Phaser.GameObjects.DOMElement;
+ private gameQualityMenuElement!: Phaser.GameObjects.DOMElement;
+ private sideMenuOpened = false;
+ private settingsMenuOpened = false;
+ private gameQualityValue: number;
+ private videoQualityValue: number;
+ private menuButton!: Phaser.GameObjects.DOMElement;
+
+ constructor() {
+ super({key: MenuSceneName});
+
+ this.gameQualityValue = localUserStore.getGameQualityValue();
+ this.videoQualityValue = localUserStore.getVideoQualityValue();
+ }
+
+ preload () {
+ this.load.html(gameMenuKey, 'resources/html/gameMenu.html');
+ this.load.html(gameMenuIconKey, 'resources/html/gameMenuIcon.html');
+ this.load.html(gameSettingsMenuKey, 'resources/html/gameQualityMenu.html');
+ }
+
+ create() {
+ this.menuElement = this.add.dom(closedSideMenuX, 25).createFromCache(gameMenuKey);
+ this.menuElement.setOrigin(0);
+
+ this.gameQualityMenuElement = this.add.dom(this.game.renderer.width / 2, -400).createFromCache(gameSettingsMenuKey);
+ this.gameQualityMenuElement.setOrigin(0.5);
+
+ this.input.keyboard.on('keyup-TAB', () => {
+ this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
+ });
+ this.menuButton = this.add.dom(35, 20).createFromCache(gameMenuIconKey);
+ this.menuButton.addListener('click');
+ this.menuButton.on('click', () => {
+ this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
+ });
+ }
+
+ openSideMenu() {
+ if (this.sideMenuOpened) return;
+ this.sideMenuOpened = true;
+ this.menuButton.getChildByID('openMenuButton').innerHTML = 'Close'
+ if (gameManager.getCurrentGameScene(this).connection.isAdmin()) {
+ const adminSection = this.menuElement.getChildByID('adminConsoleSection') as HTMLElement;
+ adminSection.hidden = false;
+ }
+ this.menuElement.addListener('click');
+ this.menuElement.on('click', this.onMenuClick.bind(this));
+ this.tweens.add({
+ targets: this.menuElement,
+ x: openedSideMenuX,
+ duration: 500,
+ ease: 'Power3'
+ });
+ }
+
+ private closeSideMenu(): void {
+ if (!this.sideMenuOpened) return;
+ this.sideMenuOpened = false;
+ this.closeGameQualityMenu()
+ this.menuButton.getChildByID('openMenuButton').innerHTML = 'Menu'
+ this.tweens.add({
+ targets: this.menuElement,
+ x: closedSideMenuX,
+ duration: 500,
+ ease: 'Power3'
+ });
+ this.menuElement.removeListener('click');
+ }
+
+
+
+ private openGameSettingsMenu(): void {
+ if (this.settingsMenuOpened) return;
+ this.settingsMenuOpened = true;
+
+ const gameQualitySelect = this.gameQualityMenuElement.getChildByID('select-game-quality') as HTMLInputElement;
+ gameQualitySelect.value = ''+this.gameQualityValue;
+ const videoQualitySelect = this.gameQualityMenuElement.getChildByID('select-video-quality') as HTMLInputElement;
+ videoQualitySelect.value = ''+this.videoQualityValue;
+
+ this.gameQualityMenuElement.addListener('click');
+ this.gameQualityMenuElement.on('click', (event:MouseEvent) => {
+ event.preventDefault();
+ if ((event?.target as HTMLInputElement).id === 'gameQualityFormSubmit') {
+ const gameQualitySelect = this.gameQualityMenuElement.getChildByID('select-game-quality') as HTMLInputElement;
+ const videoQualitySelect = this.gameQualityMenuElement.getChildByID('select-video-quality') as HTMLInputElement;
+ this.saveSetting(parseInt(gameQualitySelect.value), parseInt(videoQualitySelect.value));
+ } else if((event?.target as HTMLInputElement).id === 'gameQualityFormCancel') {
+ this.closeGameQualityMenu();
+ }
+ });
+
+ this.tweens.add({
+ targets: this.gameQualityMenuElement,
+ y: this.game.renderer.height / 2,
+ duration: 1000,
+ ease: 'Power3'
+ });
+ }
+
+ private closeGameQualityMenu(): void {
+ if (!this.settingsMenuOpened) return;
+ this.settingsMenuOpened = false;
+
+ this.gameQualityMenuElement.removeListener('click');
+ this.tweens.add({
+ targets: this.gameQualityMenuElement,
+ y: -400,
+ duration: 1000,
+ ease: 'Power3'
+ });
+ }
+
+
+
+ private onMenuClick(event:MouseEvent) {
+ event.preventDefault();
+
+ switch ((event?.target as HTMLInputElement).id) {
+ case 'changeNameButton':
+ this.closeSideMenu();
+ this.closeGameQualityMenu();
+ gameManager.leaveGame(this, LoginSceneName);
+ break;
+ case 'sparkButton':
+ this.goToSpark();
+ break;
+ case 'changeSkinButton':
+ this.closeSideMenu();
+ gameManager.leaveGame(this, SelectCharacterSceneName);
+ break;
+ case 'closeButton':
+ this.closeSideMenu();
+ break;
+ case 'shareButton':
+ this.shareUrl();
+ break;
+ case 'editGameSettingsButton':
+ this.openGameSettingsMenu();
+ break;
+ case 'adminConsoleButton':
+ gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.activeMessageConsole();
+ break;
+ }
+ }
+
+ private async shareUrl() {
+ await navigator.clipboard.writeText(location.toString());
+ alert('URL was copy to your clipboard!');
+ }
+
+ private saveSetting(valueGame: number, valueVideo: number){
+ if (valueGame !== this.gameQualityValue) {
+ this.gameQualityValue = valueGame;
+ localUserStore.setGameQualityValue(valueGame);
+ window.location.reload();
+ }
+ if (valueVideo !== this.videoQualityValue) {
+ this.videoQualityValue = valueVideo;
+ localUserStore.setVideoQualityValue(valueVideo);
+ mediaManager.updateCameraQuality(valueVideo);
+ }
+ this.closeGameQualityMenu();
+ }
+
+ private goToSpark() {
+ const sparkHost = 'https://'+window.location.host.replace('play.', 'admin.')+'/register';
+ window.location.assign(sparkHost);
+ }
+}
\ No newline at end of file
diff --git a/front/src/WebRtc/DiscussionManager.ts b/front/src/WebRtc/DiscussionManager.ts
index 053a2f44..583b1384 100644
--- a/front/src/WebRtc/DiscussionManager.ts
+++ b/front/src/WebRtc/DiscussionManager.ts
@@ -1,5 +1,5 @@
import {HtmlUtils} from "./HtmlUtils";
-import {MediaManager, ReportCallback, UpdatedLocalStreamCallback} from "./MediaManager";
+import {mediaManager, ReportCallback} from "./MediaManager";
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
@@ -13,7 +13,6 @@ export class DiscussionManager {
private divParticipants?: HTMLDivElement;
private nbpParticipants?: HTMLParagraphElement;
private divMessages?: HTMLParagraphElement;
- private buttonActiveDiscussion?: HTMLButtonElement;
private participants: Map = new Map();
@@ -23,9 +22,9 @@ export class DiscussionManager {
private userInputManager?: UserInputManager;
- constructor(private mediaManager: MediaManager, name: string) {
+ constructor() {
this.mainContainer = HtmlUtils.getElementByIdOrFail('main-container');
- this.createDiscussPart(name);
+ this.createDiscussPart(''); //todo: why do we always use empty string?
}
private createDiscussPart(name: string) {
@@ -33,20 +32,12 @@ export class DiscussionManager {
this.divDiscuss.classList.add('discussion');
const buttonCloseDiscussion: HTMLButtonElement = document.createElement('button');
- this.buttonActiveDiscussion = document.createElement('button');
buttonCloseDiscussion.classList.add('close-btn');
buttonCloseDiscussion.innerHTML = ``;
buttonCloseDiscussion.addEventListener('click', () => {
this.hideDiscussion();
- this.showButtonDiscussionBtn();
- });
- this.buttonActiveDiscussion.classList.add('active-btn');
- this.buttonActiveDiscussion.innerHTML = ``;
- this.buttonActiveDiscussion.addEventListener('click', () => {
- this.showDiscussionPart();
});
this.divDiscuss.appendChild(buttonCloseDiscussion);
- this.divDiscuss.appendChild(this.buttonActiveDiscussion);
const myName: HTMLParagraphElement = document.createElement('p');
myName.innerText = name.toUpperCase();
@@ -128,7 +119,7 @@ export class DiscussionManager {
reportBanUserAction.innerText = 'Report';
reportBanUserAction.addEventListener('click', () => {
if(reportCallback) {
- this.mediaManager.showReportModal(`${userId}`, name ?? '', reportCallback);
+ mediaManager.showReportModal(`${userId}`, name ?? '', reportCallback);
}else{
console.info('report feature is not activated!');
}
@@ -139,7 +130,6 @@ export class DiscussionManager {
this.divParticipants?.appendChild(divParticipant);
this.participants.set(userId, divParticipant);
- this.showButtonDiscussionBtn();
this.updateParticipant(this.participants.size);
}
@@ -184,9 +174,6 @@ export class DiscussionManager {
this.participants.delete(userId);
}
//if all participant leave, hide discussion button
- if(this.participants.size === 1){
- this.hideButtonDiscussionBtn();
- }
this.sendMessageCallBack.delete(userId);
}
@@ -199,14 +186,6 @@ export class DiscussionManager {
return this.activeDiscussion;
}
- private showButtonDiscussionBtn(){
- //if it's first participant, show discussion button
- if(this.activatedDiscussion || this.participants.size === 1) {
- return;
- }
- this.buttonActiveDiscussion?.classList.add('active');
- }
-
private showDiscussion(){
this.activeDiscussion = true;
if(this.userInputManager) {
@@ -222,17 +201,14 @@ export class DiscussionManager {
}
this.divDiscuss?.classList.remove('active');
}
-
- private hideButtonDiscussionBtn(){
- this.buttonActiveDiscussion?.classList.remove('active');
- }
-
+
public setUserInputManager(userInputManager : UserInputManager){
this.userInputManager = userInputManager;
}
public showDiscussionPart(){
this.showDiscussion();
- this.hideButtonDiscussionBtn();
}
-}
\ No newline at end of file
+}
+
+export const discussionManager = new DiscussionManager();
\ No newline at end of file
diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts
index 7fced45c..4aa240cd 100644
--- a/front/src/WebRtc/MediaManager.ts
+++ b/front/src/WebRtc/MediaManager.ts
@@ -1,6 +1,6 @@
import {DivImportance, layoutManager} from "./LayoutManager";
import {HtmlUtils} from "./HtmlUtils";
-import {DiscussionManager, SendMessageCallback} from "./DiscussionManager";
+import {discussionManager, SendMessageCallback} from "./DiscussionManager";
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {VIDEO_QUALITY_SELECT} from "../Administration/ConsoleGlobalMessageManager";
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -56,8 +56,6 @@ export class MediaManager {
private lastUpdateScene : Date = new Date();
private setTimeOutlastUpdateScene? : NodeJS.Timeout;
- private discussionManager: DiscussionManager;
-
private hasCamera = true;
private triggerCloseJistiFrame : Map = new Map();
@@ -120,8 +118,6 @@ export class MediaManager {
this.pingCameraStatus();
this.checkActiveUser(); //todo: desactivated in case of bug
-
- this.discussionManager = new DiscussionManager(this,'');
}
public setLastUpdateScene(){
@@ -687,11 +683,11 @@ export class MediaManager {
}
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, reportCallBack?: ReportCallback){
- this.discussionManager.addParticipant(userId, name, img, false, reportCallBack);
+ discussionManager.addParticipant(userId, name, img, false, reportCallBack);
}
public removeParticipant(userId: number|string){
- this.discussionManager.removeParticipant(userId);
+ discussionManager.removeParticipant(userId);
}
public addTriggerCloseJitsiFrameButton(id: String, Function: Function){
this.triggerCloseJistiFrame.set(id, Function);
@@ -718,24 +714,24 @@ export class MediaManager {
}
public addNewMessage(name: string, message: string, isMe: boolean = false){
- this.discussionManager.addMessage(name, message, isMe);
+ discussionManager.addMessage(name, message, isMe);
//when there are new message, show discussion
- if(!this.discussionManager.activatedDiscussion) {
- this.discussionManager.showDiscussionPart();
+ if(!discussionManager.activatedDiscussion) {
+ discussionManager.showDiscussionPart();
}
}
public addSendMessageCallback(userId: string|number, callback: SendMessageCallback){
- this.discussionManager.onSendMessageCallback(userId, callback);
+ discussionManager.onSendMessageCallback(userId, callback);
}
get activatedDiscussion(){
- return this.discussionManager.activatedDiscussion;
+ return discussionManager.activatedDiscussion;
}
public setUserInputManager(userInputManager : UserInputManager){
- this.discussionManager.setUserInputManager(userInputManager);
+ discussionManager.setUserInputManager(userInputManager);
}
//check if user is active
private checkActiveUser(){
diff --git a/front/src/index.ts b/front/src/index.ts
index 640b04f9..c8783b90 100644
--- a/front/src/index.ts
+++ b/front/src/index.ts
@@ -13,7 +13,8 @@ import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
import {ResizableScene} from "./Phaser/Login/ResizableScene";
import {EntryScene} from "./Phaser/Login/EntryScene";
import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
-import {GAME_QUALITY_SELECT} from "./Administration/ConsoleGlobalMessageManager";
+import {MenuScene} from "./Phaser/Menu/MenuScene";
+import {localUserStore} from "./Connexion/LocalUserStore";
// Load Jitsi if the environment variable is set.
if (JITSI_URL) {
@@ -24,15 +25,7 @@ if (JITSI_URL) {
const {width, height} = coWebsiteManager.getGameSize();
-let valueGameQuality : number = 60
-const localGameQuality = localStorage.getItem(GAME_QUALITY_SELECT);
-if(localGameQuality){
- try {
- valueGameQuality = parseInt(localGameQuality);
- }catch (err){
- console.error(err);
- }
-}
+const valueGameQuality = localUserStore.getGameQualityValue();
const fps : Phaser.Types.Core.FPSConfig = {
/**
* The minimum acceptable rendering rate, in frames per second.
@@ -66,9 +59,12 @@ const config: GameConfig = {
width: width / RESOLUTION,
height: height / RESOLUTION,
parent: "game",
- scene: [EntryScene, LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, FourOFourScene, CustomizeScene],
+ scene: [EntryScene, LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, FourOFourScene, CustomizeScene, MenuScene],
zoom: RESOLUTION,
fps: fps,
+ dom: {
+ createContainer: true
+ },
physics: {
default: "arcade",
arcade: {