Merge branch 'develop' of github.com:thecodingmachine/workadventure into resolution

This commit is contained in:
David Négrier 2021-05-05 11:01:11 +02:00
commit 82073098e0
120 changed files with 6228 additions and 1097 deletions

View file

@ -0,0 +1,53 @@
import {ITiledMapObject} from "../Map/ITiledMap";
import Text = Phaser.GameObjects.Text;
import {GameScene} from "../Game/GameScene";
import TextStyle = Phaser.GameObjects.TextStyle;
export class TextUtils {
public static createTextFromITiledMapObject(scene: GameScene, object: ITiledMapObject): void {
if (object.text === undefined) {
throw new Error('This object has not textual representation.');
}
const options: {
fontStyle?: string,
fontSize?: string,
fontFamily?: string,
color?: string,
align?: string,
wordWrap?: {
width: number,
useAdvancedWrap?: boolean
}
} = {};
if (object.text.italic) {
options.fontStyle = 'italic';
}
// Note: there is no support for "strikeout" and "underline"
let fontSize: number = 16;
if (object.text.pixelsize) {
fontSize = object.text.pixelsize;
}
options.fontSize = fontSize + 'px';
if (object.text.fontfamily) {
options.fontFamily = '"'+object.text.fontfamily+'"';
}
let color = '#000000';
if (object.text.color !== undefined) {
color = object.text.color;
}
options.color = color;
if (object.text.wrap === true) {
options.wordWrap = {
width: object.width,
//useAdvancedWrap: true
}
}
if (object.text.halign !== undefined) {
options.align = object.text.halign;
}
console.warn(options);
const textElem = scene.add.text(object.x, object.y, object.text.text, options);
textElem.setAngle(object.rotation);
}
}

View file

@ -89,10 +89,7 @@ export class GameManager {
console.log('starting '+ (this.currentGameSceneName || this.startRoom.id))
scenePlugin.start(this.currentGameSceneName || this.startRoom.id);
scenePlugin.launch(MenuSceneName);
if (!localUserStore.getHelpCameraSettingsShown()) {
scenePlugin.launch(HelpCameraSettingsSceneName);//700
}
scenePlugin.launch(HelpCameraSettingsSceneName);//700
}
public gameSceneIsCreated(scene: GameScene) {

View file

@ -1,4 +1,5 @@
import {ITiledMap} from "../Map/ITiledMap";
import {ITiledMap, ITiledMapLayer} from "../Map/ITiledMap";
import {LayersIterator} from "../Map/LayersIterator";
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void;
@ -10,8 +11,10 @@ export class GameMap {
private key: number|undefined;
private lastProperties = new Map<string, string|boolean|number>();
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
public readonly layersIterator: LayersIterator;
public constructor(private map: ITiledMap) {
this.layersIterator = new LayersIterator(map);
}
/**
@ -55,7 +58,7 @@ export class GameMap {
private getProperties(key: number): Map<string, string|boolean|number> {
const properties = new Map<string, string|boolean|number>();
for (const layer of this.map.layers) {
for (const layer of this.layersIterator) {
if (layer.type !== 'tilelayer') {
continue;
}

View file

@ -18,7 +18,15 @@ import {
RESOLUTION,
ZOOM_LEVEL
} from "../../Enum/EnvironmentVariable";
import {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, ITiledTileSet} from "../Map/ITiledMap";
import {
ITiledMap,
ITiledMapLayer,
ITiledMapLayerProperty,
ITiledMapObject,
ITiledText,
ITiledMapTileLayer,
ITiledTileSet
} from "../Map/ITiledMap";
import {AddPlayerInterface} from "./AddPlayerInterface";
import {PlayerAnimationDirections} from "../Player/Animation";
import {PlayerMovement} from "./PlayerMovement";
@ -78,6 +86,7 @@ import DOMElement = Phaser.GameObjects.DOMElement;
import {Subscription} from "rxjs";
import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream";
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
import {TextUtils} from "../Components/TextUtils";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick";
@ -137,7 +146,7 @@ export class GameScene extends ResizableScene implements CenterListener {
pendingEvents: Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface> = new Queue<InitUserPositionEventInterface|AddPlayerEventInterface|RemovePlayerEventInterface|UserMovedEventInterface|GroupCreatedUpdatedEventInterface|DeleteGroupEventInterface>();
private initPosition: PositionInterface|null = null;
private playersPositionInterpolator = new PlayersPositionInterpolator();
public connection!: RoomConnection;
public connection: RoomConnection|undefined;
private simplePeer!: SimplePeer;
private GlobalMessageManager!: GlobalMessageManager;
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
@ -201,7 +210,6 @@ export class GameScene extends ResizableScene implements CenterListener {
//hook preload scene
preload(): void {
addLoader(this);
const localUser = localUserStore.getLocalUser();
const textures = localUser?.textures;
if (textures) {
@ -261,6 +269,9 @@ export class GameScene extends ResizableScene implements CenterListener {
this.load.spritesheet('layout_modes', 'resources/objects/layout_modes.png', {frameWidth: 32, frameHeight: 32});
this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
//this function must stay at the end of preload function
addLoader(this);
}
// FIXME: we need to put a "unknown" instead of a "any" and validate the structure of the JSON we are receiving.
@ -369,7 +380,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.pinchManager = new PinchManager(this);
}
this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError())
this.messageSubscription = worldFullMessageStream.stream.subscribe((message) => this.showWorldFullError(message))
const playerName = gameManager.getPlayerName();
if (!playerName) {
@ -392,8 +403,9 @@ export class GameScene extends ResizableScene implements CenterListener {
//add layer on map
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
let depth = -2;
for (const layer of this.mapFile.layers) {
for (const layer of this.gameMap.layersIterator) {
if (layer.type === 'tilelayer') {
this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
@ -409,9 +421,16 @@ export class GameScene extends ResizableScene implements CenterListener {
if (layer.type === 'objectgroup' && layer.name === 'floorLayer') {
depth = 10000;
}
if (layer.type === 'objectgroup') {
for (const object of layer.objects) {
if (object.text) {
TextUtils.createTextFromITiledMapObject(this, object);
}
}
}
}
if (depth === -2) {
throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at.');
throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at. This layer cannot be contained in a group.');
}
this.initStartXAndStartY();
@ -424,8 +443,8 @@ export class GameScene extends ResizableScene implements CenterListener {
//create input to move
mediaManager.setUserInputManager(this.userInputManager);
this.userInputManager = new UserInputManager(this);
mediaManager.setUserInputManager(this.userInputManager);
if (localUserStore.getFullscreen()) {
document.querySelector('body')?.requestFullscreen();
@ -718,7 +737,7 @@ export class GameScene extends ResizableScene implements CenterListener {
if (JITSI_PRIVATE_MODE && !jitsiUrl) {
const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined;
this.connection.emitQueryJitsiJwtMessage(roomName, adminTag);
this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag);
} else {
this.startJitsi(roomName, undefined);
}
@ -741,9 +760,9 @@ export class GameScene extends ResizableScene implements CenterListener {
});
this.gameMap.onPropertyChange('silent', (newValue, oldValue) => {
if (newValue === undefined || newValue === false || newValue === '') {
this.connection.setSilent(false);
this.connection?.setSilent(false);
} else {
this.connection.setSilent(true);
this.connection?.setSilent(true);
}
});
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue, allProps) => {
@ -898,7 +917,7 @@ ${escapedMessage}
audioManager.unloadAudio();
// 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.closeAllConnections();
this.simplePeer?.closeAllConnections();
this.simplePeer?.unregister();
this.messageSubscription?.unsubscribe();
this.userInputManager.destroy();
@ -964,13 +983,14 @@ ${escapedMessage}
}
private initPositionFromLayerName(layerName: string) {
for (const layer of this.mapFile.layers) {
if (layerName === layer.name && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) {
for (const layer of this.gameMap.layersIterator) {
if ((layerName === layer.name || layer.name.endsWith('/'+layerName)) && layer.type === 'tilelayer' && (layerName === defaultStartLayerName || this.isStartLayer(layer))) {
const startPosition = this.startUser(layer);
this.startX = startPosition.x + this.mapFile.tilewidth/2;
this.startY = startPosition.y + this.mapFile.tileheight/2;
}
}
}
private getExitUrl(layer: ITiledMapLayer): string|undefined {
@ -993,7 +1013,7 @@ ${escapedMessage}
}
private getProperty(layer: ITiledMapLayer|ITiledMap, name: string): string|boolean|number|undefined {
const properties: ITiledMapLayerProperty[] = layer.properties;
const properties: ITiledMapLayerProperty[]|undefined = layer.properties;
if (!properties) {
return undefined;
}
@ -1005,7 +1025,7 @@ ${escapedMessage}
}
private getProperties(layer: ITiledMapLayer|ITiledMap, name: string): (string|number|boolean|undefined)[] {
const properties: ITiledMapLayerProperty[] = layer.properties;
const properties: ITiledMapLayerProperty[]|undefined = layer.properties;
if (!properties) {
return [];
}
@ -1019,7 +1039,7 @@ ${escapedMessage}
await gameManager.loadMap(room, this.scene);
}
private startUser(layer: ITiledMapLayer): PositionInterface {
private startUser(layer: ITiledMapTileLayer): PositionInterface {
const tiles = layer.data;
if (typeof(tiles) === 'string') {
throw new Error('The content of a JSON map must be filled as a JSON array, not as a string');
@ -1175,7 +1195,7 @@ ${escapedMessage}
this.lastMoveEventSent = event;
this.lastSentTick = this.currentTick;
const camera = this.cameras.main;
this.connection.sharePosition(event.x, event.y, event.direction, event.moving, {
this.connection?.sharePosition(event.x, event.y, event.direction, event.moving, {
left: camera.scrollX,
top: camera.scrollY,
right: camera.scrollX + camera.width,
@ -1188,7 +1208,7 @@ ${escapedMessage}
* @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate.
*/
update(time: number, delta: number) : void {
mediaManager.setLastUpdateScene();
mediaManager.updateScene();
this.currentTick = time;
this.CurrentPlayer.moveUser(delta);
@ -1241,7 +1261,7 @@ ${escapedMessage}
* Put all the players on the map on map load.
*/
private doInitUsersPosition(usersPosition: MessageUserPositionInterface[]): void {
const currentPlayerId = this.connection.getUserId();
const currentPlayerId = this.connection?.getUserId();
this.removeAllRemotePlayers();
// load map
usersPosition.forEach((userPosition : MessageUserPositionInterface) => {
@ -1385,7 +1405,7 @@ ${escapedMessage}
* Sends to the server an event emitted by one of the ActionableItems.
*/
emitActionableEvent(itemId: number, eventName: string, state: unknown, parameters: unknown) {
this.connection.emitActionableEvent(itemId, eventName, state, parameters);
this.connection?.emitActionableEvent(itemId, eventName, state, parameters);
}
public onResize(): void {
@ -1393,7 +1413,7 @@ ${escapedMessage}
// Send new viewport to server
const camera = this.cameras.main;
this.connection.setViewport({
this.connection?.setViewport({
left: camera.scrollX,
top: camera.scrollY,
right: camera.scrollX + camera.width,
@ -1448,7 +1468,7 @@ ${escapedMessage}
const jitsiUrl = allProps.get("jitsiUrl") as string|undefined;
jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl);
this.connection.setSilent(true);
this.connection?.setSilent(true);
mediaManager.hideGameOverlay();
//permit to stop jitsi when user close iframe
@ -1477,15 +1497,25 @@ ${escapedMessage}
}
//todo: put this into an 'orchestrator' scene (EntryScene?)
private showWorldFullError(): void {
private showWorldFullError(message: string|null): void {
this.cleanupClosingScene();
this.scene.stop(ReconnectingSceneName);
this.scene.remove(ReconnectingSceneName);
this.userInputManager.disableControls();
this.scene.start(ErrorSceneName, {
title: 'Connection rejected',
subTitle: 'The world you are trying to join is full. Try again later.',
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
});
//FIX ME to use status code
if(message == undefined){
this.scene.start(ErrorSceneName, {
title: 'Connection rejected',
subTitle: 'The world you are trying to join is full. Try again later.',
message: 'If you want more information, you may contact us at: workadventure@thecodingmachine.com'
});
}else{
this.scene.start(ErrorSceneName, {
title: 'Connection rejected',
subTitle: 'You cannot join the World. Try again later. \n\r \n\r Error: '+message+'.',
message: 'If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com'
});
}
}
zoomByFactor(zoomFactor: number) {

View file

@ -1,54 +1,33 @@
import {EnableCameraSceneName} from "./EnableCameraScene";
import {TextField} from "../Components/TextField";
import Image = Phaser.GameObjects.Image;
import Rectangle = Phaser.GameObjects.Rectangle;
import {loadAllLayers, loadCustomTexture} from "../Entity/PlayerTexturesLoadingManager";
import {loadAllLayers} from "../Entity/PlayerTexturesLoadingManager";
import Sprite = Phaser.GameObjects.Sprite;
import Container = Phaser.GameObjects.Container;
import {gameManager} from "../Game/GameManager";
import {ResizableScene} from "./ResizableScene";
import {localUserStore} from "../../Connexion/LocalUserStore";
import {addLoader} from "../Components/Loader";
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
import {AbstractCharacterScene} from "./AbstractCharacterScene";
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
import { MenuScene } from "../Menu/MenuScene";
import { SelectCharacterSceneName } from "./SelectCharacterScene";
import { RESOLUTION } from "../../Enum/EnvironmentVariable";
export const CustomizeSceneName = "CustomizeScene";
enum CustomizeTextures{
icon = "icon",
arrowRight = "arrow_right",
mainFont = "main_font",
arrowUp = "arrow_up",
}
export const CustomizeSceneKey = "CustomizeScene";
const customizeSceneKey = 'customizeScene';
export class CustomizeScene extends AbstractCharacterScene {
private textField!: TextField;
private enterField!: TextField;
private arrowRight!: Image;
private arrowLeft!: Image;
private arrowDown!: Image;
private arrowUp!: Image;
private Rectangle!: Rectangle;
private mobileTapUP!: Rectangle;
private mobileTapDOWN!: Rectangle;
private mobileTapLEFT!: Rectangle;
private mobileTapRIGHT!: Rectangle;
private mobileTapENTER!: Rectangle;
private logo!: Image;
private selectedLayers: number[] = [0];
private containersRow: Container[][] = [];
private activeRow:number = 0;
private layers: BodyResourceDescriptionInterface[][] = [];
private customizeSceneElement!: Phaser.GameObjects.DOMElement;
constructor() {
super({
key: CustomizeSceneName
@ -56,7 +35,7 @@ export class CustomizeScene extends AbstractCharacterScene {
}
preload() {
addLoader(this);
this.load.html(customizeSceneKey, 'resources/html/CustomCharacterScene.html');
this.layers = loadAllLayers(this.load);
this.loadCustomSceneSelectCharacters().then((bodyResourceDescriptions) => {
@ -68,105 +47,44 @@ export class CustomizeScene extends AbstractCharacterScene {
});
});
this.load.image(CustomizeTextures.arrowRight, "resources/objects/arrow_right.png");
this.load.image(CustomizeTextures.icon, "resources/logos/tcm_full.png");
this.load.image(CustomizeTextures.arrowUp, "resources/objects/arrow_up.png");
this.load.bitmapFont(CustomizeTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
//this function must stay at the end of preload function
addLoader(this);
}
create() {
this.textField = new TextField(this, this.game.renderer.width / 2, 30, 'Customize your own Avatar!');
const middleX = this.getMiddleX();
this.customizeSceneElement = this.add.dom(middleX, 0).createFromCache(customizeSceneKey);
MenuScene.revealMenusAfterInit(this.customizeSceneElement, customizeSceneKey);
this.enterField = new TextField(this, this.game.renderer.width / 2, 60, 'Start the game by pressing ENTER\n\n or touching the center rectangle');
this.customizeSceneElement.addListener('click');
this.customizeSceneElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'customizeSceneButtonLeft') {
this.moveCursorHorizontally(-1);
}else if((event?.target as HTMLInputElement).id === 'customizeSceneButtonRight') {
this.moveCursorHorizontally(1);
}else if((event?.target as HTMLInputElement).id === 'customizeSceneButtonDown') {
this.moveCursorVertically(1);
}else if((event?.target as HTMLInputElement).id === 'customizeSceneButtonUp') {
this.moveCursorVertically(-1);
}else if((event?.target as HTMLInputElement).id === 'customizeSceneFormBack') {
if(this.activeRow > 0){
this.moveCursorVertically(-1);
}else{
this.backToPreviousScene();
}
}else if((event?.target as HTMLButtonElement).id === 'customizeSceneFormSubmit') {
if(this.activeRow < 5){
this.moveCursorVertically(1);
}else{
this.nextSceneToCamera();
}
}
});
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, CustomizeTextures.icon);
this.add.existing(this.logo);
this.arrowRight = new Image(this, this.game.renderer.width*0.9, this.game.renderer.height/2, CustomizeTextures.arrowRight);
this.add.existing(this.arrowRight);
this.mobileTapRIGHT = this.add
.rectangle(
this.game.renderer.width*0.9,
this.game.renderer.height/2,
32,
32,
)
.setInteractive()
.on("pointerdown", () => {
this.moveCursorHorizontally(1);
});
this.arrowLeft = new Image(this, this.game.renderer.width/9, this.game.renderer.height/2, CustomizeTextures.arrowRight);
this.arrowLeft.flipX = true;
this.add.existing(this.arrowLeft);
this.mobileTapLEFT = this.add
.rectangle(
this.game.renderer.width/9,
this.game.renderer.height/2,
32,
32,
)
.setInteractive()
.on("pointerdown", () => {
this.moveCursorHorizontally(-1);
});
this.Rectangle = this.add.rectangle(this.cameras.main.worldView.x + this.cameras.main.width / 2, this.cameras.main.worldView.y + this.cameras.main.height / 2, 32, 33)
this.Rectangle = this.add.rectangle(this.cameras.main.worldView.x + this.cameras.main.width / 2, this.cameras.main.worldView.y + this.cameras.main.height / 3, 32, 33)
this.Rectangle.setStrokeStyle(2, 0xFFFFFF);
this.add.existing(this.Rectangle);
this.mobileTapENTER = this.add
.rectangle(
this.cameras.main.worldView.x + this.cameras.main.width / 2,
this.cameras.main.worldView.y + this.cameras.main.height / 2,
32,
32,
)
.setInteractive()
.on("pointerdown", () => {
const layers: string[] = [];
let i = 0;
for (const layerItem of this.selectedLayers) {
if (layerItem !== undefined) {
layers.push(this.layers[i][layerItem].name);
}
i++;
}
gameManager.setCharacterLayers(layers);
this.scene.sleep(CustomizeSceneName);
gameManager.tryResumingGame(this, EnableCameraSceneName);
});
this.arrowDown = new Image(this, this.game.renderer.width - 30, 100, CustomizeTextures.arrowUp);
this.arrowDown.flipY = true;
this.add.existing(this.arrowDown);
this.mobileTapDOWN = this.add
.rectangle(
this.game.renderer.width - 30,
100,
32,
32,
)
.setInteractive()
.on("pointerdown", () => {
this.moveCursorVertically(1);
});
this.arrowUp = new Image(this, this.game.renderer.width - 30, 60, CustomizeTextures.arrowUp);
this.add.existing(this.arrowUp);
this.mobileTapUP = this.add
.rectangle(
this.game.renderer.width - 30,
60,
32,
32,
)
.setInteractive()
.on("pointerdown", () => {
this.moveCursorVertically(-1);
});
this.createCustomizeLayer(0, 0, 0);
this.createCustomizeLayer(0, 0, 1);
@ -177,22 +95,10 @@ export class CustomizeScene extends AbstractCharacterScene {
this.moveLayers();
this.input.keyboard.on('keyup-ENTER', () => {
const layers: string[] = [];
let i = 0;
for (const layerItem of this.selectedLayers) {
if (layerItem !== undefined) {
layers.push(this.layers[i][layerItem].name);
}
i++;
}
if (!areCharacterLayersValid(layers)) {
return;
}
gameManager.setCharacterLayers(layers);
this.scene.sleep(CustomizeSceneName);
gameManager.tryResumingGame(this, EnableCameraSceneName);
this.nextSceneToCamera();
});
this.input.keyboard.on('keyup-BACKSPACE', () => {
this.backToPreviousScene();
});
this.input.keyboard.on('keyup-RIGHT', () => this.moveCursorHorizontally(1));
@ -222,6 +128,27 @@ export class CustomizeScene extends AbstractCharacterScene {
}
private moveCursorVertically(index:number): void {
if(index === -1 && this.activeRow === 5){
const button = this.customizeSceneElement.getChildByID('customizeSceneFormSubmit') as HTMLButtonElement;
button.innerHTML = `Next <img src="resources/objects/arrow_up.png"/>`;
}
if(index === 1 && this.activeRow === 4){
const button = this.customizeSceneElement.getChildByID('customizeSceneFormSubmit') as HTMLButtonElement;
button.innerText = 'Finish';
}
if(index === -1 && this.activeRow === 1){
const button = this.customizeSceneElement.getChildByID('customizeSceneFormBack') as HTMLButtonElement;
button.innerText = `Return`;
}
if(index === 1 && this.activeRow === 0){
const button = this.customizeSceneElement.getChildByID('customizeSceneFormBack') as HTMLButtonElement;
button.innerHTML = `Back <img src="resources/objects/arrow_up.png"/>`;
}
this.activeRow += index;
if (this.activeRow < 0) {
this.activeRow = 0
@ -236,11 +163,6 @@ export class CustomizeScene extends AbstractCharacterScene {
localUserStore.setCustomCursorPosition(this.activeRow, this.selectedLayers);
}
update(time: number, delta: number): void {
super.update(time, delta);
this.enterField.setVisible(!!(Math.floor(time / 500) % 2));
}
/**
* @param x, the layer's vertical position
* @param y, the layer's horizontal position
@ -298,7 +220,7 @@ export class CustomizeScene extends AbstractCharacterScene {
*/
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 / 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++) {
@ -337,39 +259,63 @@ export class CustomizeScene extends AbstractCharacterScene {
}
}
update(time: number, delta: number): void {
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.customizeSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
public onResize(): void {
this.moveLayers();
this.Rectangle.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
this.mobileTapENTER.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
this.Rectangle.y = this.cameras.main.worldView.y + this.cameras.main.height / 2;
this.mobileTapENTER.y = this.cameras.main.worldView.y + this.cameras.main.height / 2;
this.textField.x = this.game.renderer.width/2;
this.logo.x = this.game.renderer.width - 30;
this.logo.y = this.game.renderer.height - 20;
this.arrowUp.x = this.game.renderer.width - 30;
this.mobileTapUP.x = this.game.renderer.width - 30;
this.arrowUp.y = 60;
this.mobileTapUP.y = 60;
this.arrowDown.x = this.game.renderer.width - 30;
this.mobileTapDOWN.x = this.game.renderer.width - 30;
this.arrowDown.y = 100;
this.mobileTapDOWN.y = 100;
this.arrowLeft.x = this.game.renderer.width/9;
this.mobileTapLEFT.x = this.game.renderer.width/9;
this.arrowLeft.y = this.game.renderer.height/2;
this.mobileTapLEFT.y = this.game.renderer.height/2;
this.arrowRight.x = this.game.renderer.width*0.9;
this.mobileTapRIGHT.x = this.game.renderer.width*0.9;
this.arrowRight.y = this.game.renderer.height/2;
this.mobileTapRIGHT.y = this.game.renderer.height/2;
this.Rectangle.y = this.cameras.main.worldView.y + this.cameras.main.height / 3;
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.customizeSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
protected getMiddleX() : number{
return (this.game.renderer.width / RESOLUTION) -
(
this.customizeSceneElement
&& this.customizeSceneElement.node
&& this.customizeSceneElement.node.getBoundingClientRect().width > 0
? (this.customizeSceneElement.node.getBoundingClientRect().width / (2*RESOLUTION))
: 150
);
}
private nextSceneToCamera(){
const layers: string[] = [];
let i = 0;
for (const layerItem of this.selectedLayers) {
if (layerItem !== undefined) {
layers.push(this.layers[i][layerItem].name);
}
i++;
}
if (!areCharacterLayersValid(layers)) {
return;
}
gameManager.setCharacterLayers(layers);
this.scene.sleep(CustomizeSceneName);
this.scene.remove(SelectCharacterSceneName);
gameManager.tryResumingGame(this, EnableCameraSceneName);
}
private backToPreviousScene(){
this.scene.sleep(CustomizeSceneName);
this.scene.run(SelectCharacterSceneName);
}
}

View file

@ -10,6 +10,8 @@ import {HtmlUtils} from "../../WebRtc/HtmlUtils";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import MouseWheelToUpDown from "phaser3-rex-plugins/plugins/mousewheeltoupdown.js";
import Zone = Phaser.GameObjects.Zone;
import { MenuScene } from "../Menu/MenuScene";
export const EnableCameraSceneName = "EnableCameraScene";
enum LoginTextures {
@ -20,12 +22,11 @@ enum LoginTextures {
arrowUp = "arrow_up"
}
const enableCameraSceneKey = 'enableCameraScene';
export class EnableCameraScene extends Phaser.Scene {
private textField!: TextField;
private pressReturnField!: TextField;
private cameraNameField!: TextField;
private logo!: Image;
private arrowLeft!: Image;
private arrowRight!: Image;
private arrowDown!: Image;
@ -39,7 +40,9 @@ export class EnableCameraScene extends Phaser.Scene {
private microphoneNameField!: TextField;
private repositionCallback!: (this: Window, ev: UIEvent) => void;
private mobileTapRectangle!: Rectangle;
private enableCameraSceneElement!: Phaser.GameObjects.DOMElement;
private mobileTapZone!: Zone;
private cursorKeys!: any;
constructor() {
super({
@ -49,8 +52,10 @@ export class EnableCameraScene extends Phaser.Scene {
}
preload() {
this.load.html(enableCameraSceneKey, 'resources/html/EnableCameraScene.html');
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png");
this.load.image(LoginTextures.arrowRight, "resources/objects/arrow_right.png");
this.load.image(LoginTextures.arrowUp, "resources/objects/arrow_up.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
@ -58,6 +63,17 @@ export class EnableCameraScene extends Phaser.Scene {
}
create() {
const middleX = this.getMiddleX();
this.enableCameraSceneElement = this.add.dom(middleX, 0).createFromCache(enableCameraSceneKey);
MenuScene.revealMenusAfterInit(this.enableCameraSceneElement, enableCameraSceneKey);
const continuingButton = this.enableCameraSceneElement.getChildByID('enableCameraSceneFormSubmit') as HTMLButtonElement;
continuingButton.addEventListener('click', (e) => {
e.preventDefault();
this.login();
});
if (touchScreenManager.supportTouchScreen) {
new PinchManager(this);
}
@ -65,20 +81,13 @@ export class EnableCameraScene extends Phaser.Scene {
//Phaser.Display.Align.In.BottomCenter(this.pressReturnField, zone);
const mouseWheelToUpDown = new MouseWheelToUpDown(this);
this.cursorKeys = mouseWheelToUpDown.createCursorKeys();
this.textField = new TextField(this, this.scale.width / 2, 20, 'Turn on your camera and microphone');
this.pressReturnField = new TextField(this, this.scale.width / 2, this.scale.height - 30, 'Touch here\n\n or \n\nPress enter to start');
/* FIX ME */
this.textField = new TextField(this, this.scale.width / 2, 20, '');
// For mobile purposes - we need a big enough touchable area.
this.mobileTapRectangle = this.add
.rectangle(
this.game.renderer.width / 2,
this.game.renderer.height - 30,
200,
50,
)
.setInteractive()
.on("pointerdown", () => {
this.mobileTapZone = this.add.zone(this.scale.width / 2,this.scale.height - 30,200,50)
.setInteractive().on("pointerdown", () => {
this.login();
});
@ -108,9 +117,6 @@ export class EnableCameraScene extends Phaser.Scene {
this.arrowDown.setInteractive().on('pointerdown', this.nextMic.bind(this));
this.add.existing(this.arrowDown);
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon);
this.add.existing(this.logo);
this.input.keyboard.on('keyup-ENTER', () => {
this.login();
});
@ -221,11 +227,9 @@ export class EnableCameraScene extends Phaser.Scene {
}
this.textField.x = this.game.renderer.width / 2;
this.mobileTapRectangle.x = this.game.renderer.width / 2;
this.mobileTapZone.x = this.game.renderer.width / 2;
this.cameraNameField.x = this.game.renderer.width / 2;
this.microphoneNameField.x = this.game.renderer.width / 2;
this.pressReturnField.x = this.game.renderer.width / 2;
this.pressReturnField.x = this.game.renderer.width / 2;
this.cameraNameField.y = bounds.top / RESOLUTION - 8;
@ -245,23 +249,19 @@ export class EnableCameraScene extends Phaser.Scene {
this.arrowUp.x = this.microphoneNameField.x - this.microphoneNameField.width / 2 - 16;
this.arrowUp.y = this.microphoneNameField.y;
this.pressReturnField.y = Math.max(this.game.renderer.height - 30, this.microphoneNameField.y + 20);
this.logo.x = this.game.renderer.width - 30;
this.logo.y = Math.max(this.game.renderer.height - 20, this.microphoneNameField.y + 30);
}
update(time: number, delta: number): void {
this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2));
if (this.cursorKeys.up.isDown) {
this.cameras.main.zoom *= 1.2;
} else if(this.cursorKeys.down.isDown) {
this.cameras.main.zoom *= 0.8;
}
this.soundMeterSprite.setVolume(this.soundMeter.getVolume());
mediaManager.updateScene();
mediaManager.setLastUpdateScene();
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.enableCameraSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
private login(): void {
@ -287,4 +287,15 @@ export class EnableCameraScene extends Phaser.Scene {
}
this.updateWebCamName();
}
private getMiddleX() : number{
return (this.game.renderer.width / RESOLUTION) -
(
this.enableCameraSceneElement
&& this.enableCameraSceneElement.node
&& this.enableCameraSceneElement.node.getBoundingClientRect().width > 0
? (this.enableCameraSceneElement.node.getBoundingClientRect().width / (2*RESOLUTION))
: (300 / RESOLUTION)
);
}
}

View file

@ -26,7 +26,10 @@ export class EntryScene extends Scene {
this.scene.start(nextSceneName);
}).catch((err) => {
if (err.response && err.response.status == 404) {
ErrorScene.showError(new WAError('Page Not Found', 'Could not find map', window.location.pathname), this.scene);
ErrorScene.showError(new WAError(
'Access link incorrect',
'Could not find map. Please check your access link.',
'If you want more information, you may contact administrator or contact us at: workadventure@thecodingmachine.com'), this.scene);
} else {
ErrorScene.showError(err, this.scene);
}

View file

@ -1,30 +1,19 @@
import {gameManager} from "../Game/GameManager";
import {TextField} from "../Components/TextField";
import {TextInput} from "../Components/TextInput";
import Image = Phaser.GameObjects.Image;
import {SelectCharacterSceneName} from "./SelectCharacterScene";
import {ResizableScene} from "./ResizableScene";
import {isUserNameValid, maxUserNameLength} from "../../Connexion/LocalUser";
import { localUserStore } from "../../Connexion/LocalUserStore";
import Rectangle = Phaser.GameObjects.Rectangle;
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import {MenuScene} from "../Menu/MenuScene";
import { isUserNameValid } from "../../Connexion/LocalUser";
import { RESOLUTION } from "../../Enum/EnvironmentVariable";
//todo: put this constants in a dedicated file
export const LoginSceneName = "LoginScene";
enum LoginTextures {
icon = "icon",
mainFont = "main_font"
}
const loginSceneKey = 'loginScene';
export class LoginScene extends ResizableScene {
private nameInput!: TextInput;
private textField!: TextField;
private infoTextField!: TextField;
private pressReturnField!: TextField;
private logo!: Image;
private loginSceneElement!: Phaser.GameObjects.DOMElement;
private name: string = '';
private mobileTapRectangle!: Rectangle;
constructor() {
super({
@ -34,81 +23,82 @@ export class LoginScene extends ResizableScene {
}
preload() {
//this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.load.html(loginSceneKey, 'resources/html/loginScene.html');
}
create() {
if (touchScreenManager.supportTouchScreen) {
new PinchManager(this);
}
const middleX = this.getMiddleX();
this.loginSceneElement = this.add.dom(middleX, 0).createFromCache(loginSceneKey);
MenuScene.revealMenusAfterInit(this.loginSceneElement, loginSceneKey);
this.nameInput = new TextInput(this, this.game.renderer.width / 2, 70, maxUserNameLength, this.name,(text: string) => {
this.name = text;
localUserStore.setName(text);
})
.setInteractive()
.on('pointerdown', () => {
this.nameInput.focus();
})
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Enter your name:')
.setInteractive()
.on('pointerdown', () => {
this.nameInput.focus();
})
// For mobile purposes - we need a big enough touchable area.
this.mobileTapRectangle = this.add.rectangle(
this.game.renderer.width / 2,
130,
this.game.renderer.width / 2,
60,
).setInteractive()
.on('pointerdown', () => {
this.login(this.name)
})
this.pressReturnField = new TextField(this, this.game.renderer.width / 2, 130, 'Touch here\n\n or \n\nPress enter to start')
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon);
this.add.existing(this.logo);
const infoText = "Commands: \n - Arrows or W, A, S, D to move\n - SHIFT to run";
this.infoTextField = new TextField(this, 10, this.game.renderer.height - 35, infoText, false);
this.input.keyboard.on('keyup-ENTER', () => {
if (isUserNameValid(this.name)) {
this.login(this.name);
const pErrorElement = this.loginSceneElement.getChildByID('errorLoginScene') as HTMLInputElement;
const inputElement = this.loginSceneElement.getChildByID('loginSceneName') as HTMLInputElement;
inputElement.value = localUserStore.getName() ?? '';
inputElement.focus();
inputElement.addEventListener('keypress', (event: KeyboardEvent) => {
if(inputElement.value.length > 7){
event.preventDefault();
return;
}
pErrorElement.innerHTML = '';
if(inputElement.value && !isUserNameValid(inputElement.value)){
pErrorElement.innerHTML = 'Invalid user name: only letters and numbers are allowed. No spaces.';
}
if (event.key === 'Enter') {
event.preventDefault();
this.login(inputElement);
return;
}
});
const continuingButton = this.loginSceneElement.getChildByID('loginSceneFormSubmit') as HTMLButtonElement;
continuingButton.addEventListener('click', (e) => {
e.preventDefault();
this.login(inputElement);
});
}
update(time: number, delta: number): void {
if (this.name == '') {
this.pressReturnField?.setVisible(false);
} else {
this.pressReturnField?.setVisible(!!(Math.floor(time / 500) % 2));
private login(inputElement: HTMLInputElement): void {
const pErrorElement = this.loginSceneElement.getChildByID('errorLoginScene') as HTMLInputElement;
this.name = inputElement.value;
if (this.name === '') {
pErrorElement.innerHTML = 'The name is empty';
return
}
if(!isUserNameValid(this.name)){
pErrorElement.innerHTML = 'Invalid user name: only letters and numbers are allowed. No spaces.';
return
}
}
private login(name: string): void {
if (this.name === '') return
gameManager.setPlayerName(name);
gameManager.setPlayerName(this.name);
this.scene.stop(LoginSceneName)
gameManager.tryResumingGame(this, SelectCharacterSceneName);
this.scene.remove(LoginSceneName)
}
public onResize(ev: UIEvent): void {
this.textField.x = this.game.renderer.width / 2;
this.nameInput.setX(this.game.renderer.width / 2 - 64);
this.pressReturnField.x = this.game.renderer.width / 2;
this.mobileTapRectangle.x = this.game.renderer.width / 2;
this.logo.x = this.game.renderer.width - 30;
this.logo.y = this.game.renderer.height - 20;
this.infoTextField.y = this.game.renderer.height - 35;
update(time: number, delta: number): void {
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.loginSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
public onResize(ev: UIEvent): void {
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.loginSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
private getMiddleX() : number{
const middleX = ((window.innerWidth) - ((this.loginSceneElement && this.loginSceneElement.width > 0 ? this.loginSceneElement.width : 200 /*FIXME to use a const will be injected in HTMLElement*/)*2)) / 2;
return (middleX > 0 ? (middleX / 2) : 0);
}
}

View file

@ -0,0 +1,76 @@
import {gameManager} from "../Game/GameManager";
import {TextField} from "../Components/TextField";
import Image = Phaser.GameObjects.Image;
import Rectangle = Phaser.GameObjects.Rectangle;
import {EnableCameraSceneName} from "./EnableCameraScene";
import {CustomizeSceneName} from "./CustomizeScene";
import {localUserStore} from "../../Connexion/LocalUserStore";
import {loadAllDefaultModels} from "../Entity/PlayerTexturesLoadingManager";
import {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
import {AbstractCharacterScene} from "./AbstractCharacterScene";
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import {MenuScene} from "../Menu/MenuScene";
import { SelectCharacterScene, SelectCharacterSceneName } from "./SelectCharacterScene";
export class SelectCharacterMobileScene extends SelectCharacterScene {
create(){
super.create();
this.selectedRectangle.destroy();
}
protected defineSetupPlayer(numero: number){
const deltaX = 30;
const deltaY = 2;
let [playerX, playerY] = this.getCharacterPosition();
let playerVisible = true;
let playerScale = 1.5;
let playserOpactity = 1;
if( this.currentSelectUser !== numero ){
playerVisible = false;
}
if( numero === (this.currentSelectUser + 1) ){
playerY -= deltaY;
playerX += deltaX;
playerScale = 0.8;
playserOpactity = 0.6;
playerVisible = true;
}
if( numero === (this.currentSelectUser + 2) ){
playerY -= deltaY;
playerX += (deltaX * 2);
playerScale = 0.8;
playserOpactity = 0.6;
playerVisible = true;
}
if( numero === (this.currentSelectUser - 1) ){
playerY -= deltaY;
playerX -= deltaX;
playerScale = 0.8;
playserOpactity = 0.6;
playerVisible = true;
}
if( numero === (this.currentSelectUser - 2) ){
playerY -= deltaY;
playerX -= (deltaX * 2);
playerScale = 0.8;
playserOpactity = 0.6;
playerVisible = true;
}
return {playerX, playerY, playerScale, playserOpactity, playerVisible}
}
/**
* Returns pixel position by on column and row number
*/
protected getCharacterPosition(): [number, number] {
return [
this.game.renderer.width / 2,
this.game.renderer.height / 3
];
}
}

View file

@ -1,5 +1,4 @@
import {gameManager} from "../Game/GameManager";
import {TextField} from "../Components/TextField";
import Image = Phaser.GameObjects.Image;
import Rectangle = Phaser.GameObjects.Rectangle;
import {EnableCameraSceneName} from "./EnableCameraScene";
@ -12,268 +11,265 @@ import {AbstractCharacterScene} from "./AbstractCharacterScene";
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import {MenuScene} from "../Menu/MenuScene";
import { SelectCharacterMobileScene } from "./SelectCharacterMobileScene";
//todo: put this constants in a dedicated file
export const SelectCharacterSceneName = "SelectCharacterScene";
enum LoginTextures {
playButton = "play_button",
icon = "icon",
mainFont = "main_font",
customizeButton = "customize_button",
customizeButtonSelected = "customize_button_selected"
}
const selectCharacterKey = 'selectCharacterScene';
export class SelectCharacterScene extends AbstractCharacterScene {
private readonly nbCharactersPerRow = 6;
private textField!: TextField;
private pressReturnField!: TextField;
private logo!: Image;
private customizeButton!: Image;
private customizeButtonSelected!: Image;
protected readonly nbCharactersPerRow = 6;
protected selectedPlayer!: Phaser.Physics.Arcade.Sprite|null; // null if we are selecting the "customize" option
protected players: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
protected playerModels!: BodyResourceDescriptionInterface[];
private selectedRectangle!: Rectangle;
private selectedRectangleXPos = 0; // Number of the character selected in the rows
private selectedRectangleYPos = 0; // Number of the character selected in the columns
private selectedPlayer!: Phaser.Physics.Arcade.Sprite|null; // null if we are selecting the "customize" option
private players: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
private mobileTapRectangle!: Rectangle;
private playerModels!: BodyResourceDescriptionInterface[];
protected selectedRectangle!: Rectangle;
protected selectCharacterSceneElement!: Phaser.GameObjects.DOMElement;
protected currentSelectUser = 0;
constructor() {
super({
key: SelectCharacterSceneName
key: SelectCharacterSceneName,
});
}
preload() {
addLoader(this);
this.load.html(selectCharacterKey, 'resources/html/selectCharacterScene.html');
this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => {
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
this.playerModels.push(bodyResourceDescription);
});
})
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
this.playerModels = loadAllDefaultModels(this.load);
this.load.image(LoginTextures.customizeButton, 'resources/objects/customize.png');
this.load.image(LoginTextures.customizeButtonSelected, 'resources/objects/customize_selected.png');
//this function must stay at the end of preload function
addLoader(this);
}
create() {
const middleX = this.getMiddleX();
this.selectCharacterSceneElement = this.add.dom(middleX, 0).createFromCache(selectCharacterKey);
MenuScene.revealMenusAfterInit(this.selectCharacterSceneElement, selectCharacterKey);
this.selectCharacterSceneElement.addListener('click');
this.selectCharacterSceneElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'selectCharacterButtonLeft') {
this.moveToLeft();
}else if((event?.target as HTMLInputElement).id === 'selectCharacterButtonRight') {
this.moveToRight();
}else if((event?.target as HTMLInputElement).id === 'selectCharacterSceneFormSubmit') {
this.nextSceneToCameraScene();
}else if((event?.target as HTMLInputElement).id === 'selectCharacterSceneFormCustomYourOwnSubmit') {
this.nextSceneToCustomizeScene();
}
});
if (touchScreenManager.supportTouchScreen) {
new PinchManager(this);
}
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Select your character');
this.pressReturnField = new TextField(
this,
this.game.renderer.width / 2,
90 + 32 * Math.ceil( this.playerModels.length / this.nbCharactersPerRow) + 60,
'Touch here\n\n or \n\nPress enter to start');
// For mobile purposes - we need a big enough touchable area.
this.mobileTapRectangle = this.add
.rectangle(
this.game.renderer.width / 2,
275,
this.game.renderer.width / 2,
50,
)
.setInteractive()
.on("pointerdown", () => {
this.nextScene();
});
const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xFFFFFF);
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon);
this.add.existing(this.logo);
this.input.keyboard.on('keyup-ENTER', () => {
return this.nextScene();
});
this.input.keyboard.on('keydown-RIGHT', () => {
if(this.selectedRectangleYPos * this.nbCharactersPerRow + (this.selectedRectangleXPos + 2))
if (
this.selectedRectangleXPos < this.nbCharactersPerRow - 1
&& ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos + 1) + 1) <= this.playerModels.length
) {
this.selectedRectangleXPos++;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-LEFT', () => {
if (
this.selectedRectangleXPos > 0
&& ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos - 1) + 1) <= this.playerModels.length
) {
this.selectedRectangleXPos--;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-DOWN', () => {
if (
this.selectedRectangleYPos < Math.ceil(this.playerModels.length / this.nbCharactersPerRow)
&& (
(((this.selectedRectangleYPos + 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.playerModels.length // check if player isn't empty
|| (this.selectedRectangleYPos + 1) === Math.ceil(this.playerModels.length / this.nbCharactersPerRow) // check if is custom rectangle
)
) {
this.selectedRectangleYPos++;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-UP', () => {
if (
this.selectedRectangleYPos > 0
&& (((this.selectedRectangleYPos - 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.playerModels.length
) {
this.selectedRectangleYPos--;
}
this.updateSelectedPlayer();
});
this.selectedRectangle.setDepth(2);
/*create user*/
this.createCurrentPlayer();
const playerNumber = localUserStore.getPlayerCharacterIndex();
if (playerNumber && playerNumber !== -1) {
this.selectedRectangleXPos = playerNumber % this.nbCharactersPerRow;
this.selectedRectangleYPos = Math.floor(playerNumber / this.nbCharactersPerRow);
this.updateSelectedPlayer();
} else if (playerNumber === -1) {
this.selectedRectangleYPos = Math.ceil(this.playerModels.length / this.nbCharactersPerRow);
this.updateSelectedPlayer();
}
this.input.keyboard.on('keyup-ENTER', () => {
return this.nextSceneToCameraScene();
});
this.input.keyboard.on('keydown-RIGHT', () => {
this.moveToRight();
});
this.input.keyboard.on('keydown-LEFT', () => {
this.moveToLeft();
});
this.input.keyboard.on('keydown-UP', () => {
this.moveToUp();
});
this.input.keyboard.on('keydown-DOWN', () => {
this.moveToDown();
});
}
update(time: number, delta: number): void {
this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2));
}
private nextScene(): void {
protected nextSceneToCameraScene(): void {
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
return;
}
this.scene.stop(SelectCharacterSceneName);
if (this.selectedPlayer !== null) {
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
gameManager.tryResumingGame(this, EnableCameraSceneName);
} else {
this.scene.run(CustomizeSceneName);
if(!this.selectedPlayer){
return;
}
this.scene.stop(SelectCharacterSceneName);
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
gameManager.tryResumingGame(this, EnableCameraSceneName);
this.scene.remove(SelectCharacterSceneName);
}
protected nextSceneToCustomizeScene(): void {
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
return;
}
this.scene.sleep(SelectCharacterSceneName);
this.scene.run(CustomizeSceneName);
}
createCurrentPlayer(): void {
for (let i = 0; i <this.playerModels.length; i++) {
const playerResource = this.playerModels[i];
const col = i % this.nbCharactersPerRow;
const row = Math.floor(i / this.nbCharactersPerRow);
const [x, y] = this.getCharacterPosition(col, row);
const player = this.physics.add.sprite(x, y, playerResource.name, 0);
player.setBounce(0.2);
player.setCollideWorldBounds(true);
const [middleX, middleY] = this.getCharacterPosition();
const player = this.physics.add.sprite(middleX, middleY, playerResource.name, 0);
this.setUpPlayer(player, i);
this.anims.create({
key: playerResource.name,
frames: this.anims.generateFrameNumbers(playerResource.name, {start: 0, end: 2,}),
frameRate: 10,
frames: this.anims.generateFrameNumbers(playerResource.name, {start: 0, end: 11}),
frameRate: 8,
repeat: -1
});
player.setInteractive().on("pointerdown", () => {
this.selectedRectangleXPos = col;
this.selectedRectangleYPos = row;
this.updateSelectedPlayer();
if(this.currentSelectUser === i){
return;
}
this.currentSelectUser = i;
this.moveUser();
});
this.players.push(player);
}
const maxRow = Math.ceil( this.playerModels.length / this.nbCharactersPerRow);
this.customizeButton = new Image(this, this.game.renderer.width / 2, 90 + 32 * maxRow + 6, LoginTextures.customizeButton);
this.customizeButton.setOrigin(0.5, 0.5);
this.add.existing(this.customizeButton);
this.customizeButtonSelected = new Image(this, this.game.renderer.width / 2, 90 + 32 * maxRow + 6, LoginTextures.customizeButtonSelected);
this.customizeButtonSelected.setOrigin(0.5, 0.5);
this.customizeButtonSelected.setVisible(false);
this.add.existing(this.customizeButtonSelected);
this.selectedPlayer = this.players[this.currentSelectUser];
this.selectedPlayer.play(this.playerModels[this.currentSelectUser].name);
}
this.customizeButton.setInteractive().on("pointerdown", () => {
this.selectedRectangleYPos = Math.ceil(this.playerModels.length / this.nbCharactersPerRow);
this.updateSelectedPlayer();
this.nextScene();
});
this.customizeButtonSelected.setInteractive().on("pointerdown", () => {
this.nextScene();
});
protected moveUser(){
for(let i = 0; i < this.players.length; i++){
const player = this.players[i];
this.setUpPlayer(player, i);
}
this.updateSelectedPlayer();
}
this.selectedPlayer = this.players[0];
this.selectedPlayer.play(this.playerModels[0].name);
protected moveToLeft(){
if(this.currentSelectUser === 0){
return;
}
this.currentSelectUser -= 1;
this.moveUser();
}
protected moveToRight(){
if(this.currentSelectUser === (this.players.length - 1)){
return;
}
this.currentSelectUser += 1;
this.moveUser();
}
protected moveToUp(){
if(this.currentSelectUser < this.nbCharactersPerRow){
return;
}
this.currentSelectUser -= this.nbCharactersPerRow;
this.moveUser();
}
protected moveToDown(){
if((this.currentSelectUser + this.nbCharactersPerRow) > (this.players.length - 1)){
return;
}
this.currentSelectUser += this.nbCharactersPerRow;
this.moveUser();
}
protected defineSetupPlayer(numero: number){
const deltaX = 32;
const deltaY = 32;
let [playerX, playerY] = this.getCharacterPosition(); // player X and player y are middle of the
playerX = ( (playerX - (deltaX * 2.5)) + ((deltaX) * (numero % this.nbCharactersPerRow)) ); // calcul position on line users
playerY = ( (playerY - (deltaY * 2)) + ((deltaY) * ( Math.floor(numero / this.nbCharactersPerRow) )) ); // calcul position on column users
const playerVisible = true;
const playerScale = 1;
const playserOpactity = 1;
// if selected
if( numero === this.currentSelectUser ){
this.selectedRectangle.setX(playerX);
this.selectedRectangle.setY(playerY);
}
return {playerX, playerY, playerScale, playserOpactity, playerVisible}
}
protected setUpPlayer(player: Phaser.Physics.Arcade.Sprite, numero: number){
const {playerX, playerY, playerScale, playserOpactity, playerVisible} = this.defineSetupPlayer(numero);
player.setBounce(0.2);
player.setCollideWorldBounds(true);
player.setVisible( playerVisible );
player.setScale(playerScale, playerScale);
player.setAlpha(playserOpactity);
player.setX(playerX);
player.setY(playerY);
}
/**
* Returns pixel position by on column and row number
*/
private getCharacterPosition(x: number, y: number): [number, number] {
protected getCharacterPosition(): [number, number] {
return [
this.game.renderer.width / 2 + 16 + (x - this.nbCharactersPerRow / 2) * 32,
y * 32 + 90
this.game.renderer.width / 2,
this.game.renderer.height / 2.5
];
}
private updateSelectedPlayer(): void {
this.selectedPlayer?.anims.pause();
// If we selected the customize button
if (this.selectedRectangleYPos === Math.ceil(this.playerModels.length / this.nbCharactersPerRow)) {
this.selectedPlayer = null;
this.selectedRectangle.setVisible(false);
this.customizeButtonSelected.setVisible(true);
this.customizeButton.setVisible(false);
localUserStore.setPlayerCharacterIndex(-1);
return;
}
this.customizeButtonSelected.setVisible(false);
this.customizeButton.setVisible(true);
const [x, y] = this.getCharacterPosition(this.selectedRectangleXPos, this.selectedRectangleYPos);
this.selectedRectangle.setVisible(true);
this.selectedRectangle.setX(x);
this.selectedRectangle.setY(y);
this.selectedRectangle.setSize(32, 32);
const playerNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow;
const player = this.players[playerNumber];
player.play(this.playerModels[playerNumber].name);
protected updateSelectedPlayer(): void {
this.selectedPlayer?.anims.pause(this.selectedPlayer?.anims.currentAnim.frames[0]);
const player = this.players[this.currentSelectUser];
player.play(this.playerModels[this.currentSelectUser].name);
this.selectedPlayer = player;
localUserStore.setPlayerCharacterIndex(playerNumber);
localUserStore.setPlayerCharacterIndex(this.currentSelectUser);
}
update(time: number, delta: number): void {
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.selectCharacterSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
public onResize(ev: UIEvent): void {
this.textField.x = this.game.renderer.width / 2;
this.pressReturnField.x = this.game.renderer.width / 2;
this.logo.x = this.game.renderer.width - 30;
this.logo.y = this.game.renderer.height - 20;
this.customizeButton.x = this.game.renderer.width / 2;
this.customizeButtonSelected.x = this.game.renderer.width / 2;
//move position of user
this.moveUser();
for (let i = 0; i <this.playerModels.length; i++) {
const player = this.players[i];
const col = i % this.nbCharactersPerRow;
const row = Math.floor(i / this.nbCharactersPerRow);
const [x, y] = this.getCharacterPosition(col, row);
player.x = x;
player.y = y;
}
this.updateSelectedPlayer();
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.selectCharacterSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
protected getMiddleX() : number{
return (this.game.renderer.width / 2) -
(
this.selectCharacterSceneElement
&& this.selectCharacterSceneElement.node
&& this.selectCharacterSceneElement.node.getBoundingClientRect().width > 0
? (this.selectCharacterSceneElement.node.getBoundingClientRect().width / 4)
: 150
);
}
}

View file

@ -3,35 +3,26 @@ import Rectangle = Phaser.GameObjects.Rectangle;
import { addLoader } from "../Components/Loader";
import { gameManager} from "../Game/GameManager";
import { ResizableScene } from "./ResizableScene";
import { TextField } from "../Components/TextField";
import { EnableCameraSceneName } from "./EnableCameraScene";
import { localUserStore } from "../../Connexion/LocalUserStore";
import { CompanionResourceDescriptionInterface } from "../Companion/CompanionTextures";
import { getAllCompanionResources } from "../Companion/CompanionTexturesLoadingManager";
import {touchScreenManager} from "../../Touch/TouchScreenManager";
import {PinchManager} from "../UserInput/PinchManager";
import { MenuScene } from "../Menu/MenuScene";
import { RESOLUTION } from "../../Enum/EnvironmentVariable";
export const SelectCompanionSceneName = "SelectCompanionScene";
enum LoginTextures {
playButton = "play_button",
icon = "icon",
mainFont = "main_font"
}
const selectCompanionSceneKey = 'selectCompanionScene';
export class SelectCompanionScene extends ResizableScene {
private logo!: Image;
private textField!: TextField;
private pressReturnField!: TextField;
private readonly nbCharactersPerRow = 7;
private selectedRectangle!: Rectangle;
private selectedCompanion!: Phaser.Physics.Arcade.Sprite;
private companions: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
private companionModels: Array<CompanionResourceDescriptionInterface|null> = [null];
private companionModels: Array<CompanionResourceDescriptionInterface> = [];
private confirmTouchArea!: Rectangle;
private selectCompanionSceneElement!: Phaser.GameObjects.DOMElement;
private currentCompanion = 0;
constructor() {
super({
@ -40,210 +31,222 @@ export class SelectCompanionScene extends ResizableScene {
}
preload() {
addLoader(this);
this.load.html(selectCompanionSceneKey, 'resources/html/SelectCompanionScene.html');
getAllCompanionResources(this.load).forEach(model => {
this.companionModels.push(model);
});
this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png");
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
//this function must stay at the end of preload function
addLoader(this);
}
create() {
const middleX = this.getMiddleX();
this.selectCompanionSceneElement = this.add.dom(middleX, 0).createFromCache(selectCompanionSceneKey);
MenuScene.revealMenusAfterInit(this.selectCompanionSceneElement, selectCompanionSceneKey);
this.selectCompanionSceneElement.addListener('click');
this.selectCompanionSceneElement.on('click', (event:MouseEvent) => {
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'selectCharacterButtonLeft') {
this.moveToLeft();
}else if((event?.target as HTMLInputElement).id === 'selectCharacterButtonRight') {
this.moveToRight();
}else if((event?.target as HTMLInputElement).id === 'selectCompanionSceneFormSubmit') {
this.nextScene();
}else if((event?.target as HTMLInputElement).id === 'selectCompanionSceneFormBack') {
this._nextScene();
}
});
if (touchScreenManager.supportTouchScreen) {
new PinchManager(this);
}
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Select your companion');
const confirmTouchAreaY = 115 + 32 * Math.ceil(this.companionModels.length / this.nbCharactersPerRow);
this.pressReturnField = new TextField(
this,
this.game.renderer.width / 2,
confirmTouchAreaY,
'Touch here\n\n or \n\n press enter to start'
);
this.confirmTouchArea = this.add
.rectangle(this.game.renderer.width / 2, confirmTouchAreaY, 200, 50)
.setInteractive()
.on("pointerdown", this.nextScene.bind(this));
const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xFFFFFF);
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon);
this.add.existing(this.logo);
// input events
this.input.keyboard.on('keyup-ENTER', this.nextScene.bind(this));
this.input.keyboard.on('keydown-RIGHT', this.selectNext.bind(this));
this.input.keyboard.on('keydown-LEFT', this.selectPrevious.bind(this));
this.input.keyboard.on('keydown-DOWN', this.jumpToNextRow.bind(this));
this.input.keyboard.on('keydown-UP', this.jumpToPreviousRow.bind(this));
this.input.keyboard.on('keydown-RIGHT', this.moveToRight.bind(this));
this.input.keyboard.on('keydown-LEFT', this.moveToLeft.bind(this));
if(localUserStore.getCompanion()){
const companionIndex = this.companionModels.findIndex((companion) => companion.name === localUserStore.getCompanion());
if(companionIndex > -1 || companionIndex < this.companions.length){
this.currentCompanion = companionIndex;
this.selectedCompanion = this.companions[companionIndex];
}
}
localUserStore.setCompanion(null);
gameManager.setCompanion(null);
this.createCurrentCompanion();
this.selectCompanion(this.getCompanionIndex());
this.updateSelectedCompanion();
}
update(time: number, delta: number): void {
this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2));
}
private jumpToPreviousRow(): void {
const index = this.companions.indexOf(this.selectedCompanion) - this.nbCharactersPerRow;
if (index >= 0) {
this.selectCompanion(index);
}
}
private jumpToNextRow(): void {
const index = this.companions.indexOf(this.selectedCompanion) + this.nbCharactersPerRow;
if (index < this.companions.length) {
this.selectCompanion(index);
}
}
private selectPrevious(): void {
const index = this.companions.indexOf(this.selectedCompanion);
this.selectCompanion(index - 1);
}
private selectNext(): void {
const index = this.companions.indexOf(this.selectedCompanion);
this.selectCompanion(index + 1);
}
private selectCompanion(index?: number): void {
if (typeof index === 'undefined') {
index = this.companions.indexOf(this.selectedCompanion);
}
// make sure index is inside possible range
index = Math.min(this.companions.length - 1, Math.max(0, index));
if (this.selectedCompanion === this.companions[index]) {
return;
}
this.selectedCompanion.anims.pause();
this.selectedCompanion = this.companions[index];
this.redrawSelectedRectangle();
const model = this.companionModels[index];
if (model !== null) {
this.selectedCompanion.anims.play(model.name);
}
}
private redrawSelectedRectangle(): void {
this.selectedRectangle.setVisible(true);
this.selectedRectangle.setX(this.selectedCompanion.x);
this.selectedRectangle.setY(this.selectedCompanion.y);
this.selectedRectangle.setSize(32, 32);
}
private storeCompanionSelection(): string|null {
const index = this.companions.indexOf(this.selectedCompanion);
const model = this.companionModels[index];
const companion = model === null ? null : model.name;
localUserStore.setCompanion(companion);
return companion;
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.selectCompanionSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
private nextScene(): void {
const companion = this.storeCompanionSelection();
localUserStore.setCompanion(this.companionModels[this.currentCompanion].name);
gameManager.setCompanion(this.companionModels[this.currentCompanion].name);
this._nextScene();
}
private _nextScene(){
// next scene
this.scene.stop(SelectCompanionSceneName);
gameManager.setCompanion(companion);
gameManager.tryResumingGame(this, EnableCameraSceneName);
this.scene.remove(SelectCompanionSceneName);
}
private createCurrentCompanion(): void {
for (let i = 0; i < this.companionModels.length; i++) {
const companionResource = this.companionModels[i];
const col = i % this.nbCharactersPerRow;
const row = Math.floor(i / this.nbCharactersPerRow);
const [x, y] = this.getCharacterPosition(col, row);
let name = "null";
if (companionResource !== null) {
name = companionResource.name;
}
const companion = this.physics.add.sprite(x, y, name, 0);
companion.setBounce(0.2);
companion.setCollideWorldBounds(true);
if (companionResource !== null) {
this.anims.create({
key: name,
frames: this.anims.generateFrameNumbers(name, {start: 0, end: 2,}),
frameRate: 10,
repeat: -1
});
}
const companionResource = this.companionModels[i]
const [middleX, middleY] = this.getCompanionPosition();
const companion = this.physics.add.sprite(middleX, middleY, companionResource.name, 0);
this.setUpCompanion(companion, i);
this.anims.create({
key: companionResource.name,
frames: this.anims.generateFrameNumbers(companionResource.name, {start: 0, end: 2,}),
frameRate: 10,
repeat: -1
});
companion.setInteractive().on("pointerdown", () => {
this.selectCompanion(i);
this.currentCompanion = i;
this.moveCompanion();
});
this.companions.push(companion);
}
this.selectedCompanion = this.companions[0];
}
private getCharacterPosition(x: number, y: number): [number, number] {
return [
this.game.renderer.width / 2 + 16 + (x - this.nbCharactersPerRow / 2) * 32,
y * 32 + 90
];
this.selectedCompanion = this.companions[this.currentCompanion];
}
public onResize(ev: UIEvent): void {
this.textField.x = this.game.renderer.width / 2;
this.pressReturnField.x = this.game.renderer.width / 2;
this.logo.x = this.game.renderer.width - 30;
this.logo.y = this.game.renderer.height - 20;
this.moveCompanion();
for (let i = 0; i < this.companionModels.length; i++) {
const companion = this.companions[i];
const col = i % this.nbCharactersPerRow;
const row = Math.floor(i / this.nbCharactersPerRow);
const [x, y] = this.getCharacterPosition(col, row);
companion.x = x;
companion.y = y;
}
this.redrawSelectedRectangle();
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.selectCompanionSceneElement,
x: middleX,
duration: 1000,
ease: 'Power3'
});
}
private getCompanionIndex(): number {
const companion = localUserStore.getCompanion();
private updateSelectedCompanion(): void {
this.selectedCompanion?.anims.pause();
const companion = this.companions[this.currentCompanion];
companion.play(this.companionModels[this.currentCompanion].name);
this.selectedCompanion = companion;
}
if (companion === null) {
return 0;
private moveCompanion(){
for(let i = 0; i < this.companions.length; i++){
const companion = this.companions[i];
this.setUpCompanion(companion, i);
}
this.updateSelectedCompanion();
}
return this.companionModels.findIndex(model => model !== null && model.name === companion);
private moveToLeft(){
if(this.currentCompanion === 0){
return;
}
this.currentCompanion -= 1;
this.moveCompanion();
}
private moveToRight(){
if(this.currentCompanion === (this.companions.length - 1)){
return;
}
this.currentCompanion += 1;
this.moveCompanion();
}
private defineSetupCompanion(numero: number){
const deltaX = 30;
const deltaY = 2;
let [companionX, companionY] = this.getCompanionPosition();
let companionVisible = true;
let companionScale = 1.5;
let companionOpactity = 1;
if( this.currentCompanion !== numero ){
companionVisible = false;
}
if( numero === (this.currentCompanion + 1) ){
companionY -= deltaY;
companionX += deltaX;
companionScale = 0.8;
companionOpactity = 0.6;
companionVisible = true;
}
if( numero === (this.currentCompanion + 2) ){
companionY -= deltaY;
companionX += (deltaX * 2);
companionScale = 0.8;
companionOpactity = 0.6;
companionVisible = true;
}
if( numero === (this.currentCompanion - 1) ){
companionY -= deltaY;
companionX -= deltaX;
companionScale = 0.8;
companionOpactity = 0.6;
companionVisible = true;
}
if( numero === (this.currentCompanion - 2) ){
companionY -= deltaY;
companionX -= (deltaX * 2);
companionScale = 0.8;
companionOpactity = 0.6;
companionVisible = true;
}
return {companionX, companionY, companionScale, companionOpactity, companionVisible}
}
/**
* Returns pixel position by on column and row number
*/
private getCompanionPosition(): [number, number] {
return [
this.game.renderer.width / 2,
this.game.renderer.height / 3
];
}
private setUpCompanion(companion: Phaser.Physics.Arcade.Sprite, numero: number){
const {companionX, companionY, companionScale, companionOpactity, companionVisible} = this.defineSetupCompanion(numero);
companion.setBounce(0.2);
companion.setCollideWorldBounds(true);
companion.setVisible( companionVisible );
companion.setScale(companionScale, companionScale);
companion.setAlpha(companionOpactity);
companion.setX(companionX);
companion.setY(companionY);
}
private getMiddleX() : number{
return (this.game.renderer.width / RESOLUTION) -
(
this.selectCompanionSceneElement
&& this.selectCompanionSceneElement.node
&& this.selectCompanionSceneElement.node.getBoundingClientRect().width > 0
? (this.selectCompanionSceneElement.node.getBoundingClientRect().width / (2*RESOLUTION))
: 150
);
}
}

View file

@ -14,7 +14,7 @@ export interface ITiledMap {
* Map orientation (orthogonal)
*/
orientation: string;
properties: ITiledMapLayerProperty[];
properties?: ITiledMapLayerProperty[];
/**
* Render order (right-down)
@ -24,6 +24,11 @@ export interface ITiledMap {
tilewidth: number;
tilesets: ITiledTileSet[];
version: number;
compressionlevel?: number;
infinite?: boolean;
nextlayerid?: number;
tiledversion?: string;
type?: string;
}
export interface ITiledMapLayerProperty {
@ -38,19 +43,35 @@ export interface ITiledMapLayerProperty {
value: boolean
}*/
export interface ITiledMapLayer {
export type ITiledMapLayer = ITiledMapGroupLayer | ITiledMapObjectLayer | ITiledMapTileLayer;
export interface ITiledMapGroupLayer {
id?: number,
name: string;
opacity: number;
properties?: ITiledMapLayerProperty[];
type: "group";
visible: boolean;
x: number;
y: number;
/**
* Layers for group layer
*/
layers: ITiledMapLayer[];
}
export interface ITiledMapTileLayer {
id?: number,
data: number[]|string;
height: number;
name: string;
opacity: number;
properties: ITiledMapLayerProperty[];
encoding: string;
properties?: ITiledMapLayerProperty[];
encoding?: string;
compression?: string;
/**
* Type of layer (tilelayer, objectgroup)
*/
type: string;
type: "tilelayer";
visible: boolean;
width: number;
x: number;
@ -59,7 +80,28 @@ export interface ITiledMapLayer {
/**
* Draw order (topdown (default), index)
*/
draworder: string;
draworder?: string;
}
export interface ITiledMapObjectLayer {
id?: number,
height: number;
name: string;
opacity: number;
properties?: ITiledMapLayerProperty[];
encoding?: string;
compression?: string;
type: "objectgroup";
visible: boolean;
width: number;
x: number;
y: number;
/**
* Draw order (topdown (default), index)
*/
draworder?: string;
objects: ITiledMapObject[];
}
@ -94,6 +136,20 @@ export interface ITiledMapObject {
* Polyline points
*/
polyline: {x: number, y: number}[];
text?: ITiledText
}
export interface ITiledText {
text: string,
wrap?: boolean,
fontfamily?: string,
pixelsize?: number,
color?: string,
underline?: boolean,
italic?: boolean,
strikeout?: boolean,
halign?: "center"|"right"|"justify"|"left"
}
export interface ITiledTileSet {

View file

@ -0,0 +1,44 @@
import {ITiledMap, ITiledMapLayer} from "./ITiledMap";
/**
* Iterates over the layers of a map, flattening the grouped layers
*/
export class LayersIterator implements IterableIterator<ITiledMapLayer> {
private layers: ITiledMapLayer[] = [];
private pointer: number = 0;
constructor(private map: ITiledMap) {
this.initLayersList(map.layers, '');
}
private initLayersList(layers : ITiledMapLayer[], prefix : string) {
for (const layer of layers) {
if (layer.type === 'group') {
this.initLayersList(layer.layers, prefix + layer.name + '/');
} else {
const layerWithNewName = { ...layer };
layerWithNewName.name = prefix+layerWithNewName.name;
this.layers.push(layerWithNewName);
}
}
}
public next(): IteratorResult<ITiledMapLayer> {
if (this.pointer < this.layers.length) {
return {
done: false,
value: this.layers[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
[Symbol.iterator](): IterableIterator<ITiledMapLayer> {
return new LayersIterator(this.map);
}
}

View file

@ -1,6 +1,7 @@
import {mediaManager} from "../../WebRtc/MediaManager";
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
import {localUserStore} from "../../Connexion/LocalUserStore";
import { RESOLUTION } from "../../Enum/EnvironmentVariable";
export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene';
const helpCameraSettings = 'helpCameraSettings';
@ -20,16 +21,18 @@ export class HelpCameraSettingsScene extends Phaser.Scene {
}
create(){
localUserStore.setHelpCameraSettingsShown();
this.createHelpCameraSettings();
}
private createHelpCameraSettings() : void {
const middleX = (window.innerWidth / 3) - (370*0.85);
const middleX = this.getMiddleX();
this.helpCameraSettingsElement = this.add.dom(middleX, -800, undefined, {overflow: 'scroll'}).createFromCache(helpCameraSettings);
this.revealMenusAfterInit(this.helpCameraSettingsElement, helpCameraSettings);
this.helpCameraSettingsElement.addListener('click');
this.helpCameraSettingsElement.on('click', (event:MouseEvent) => {
if((event?.target as HTMLInputElement).id === 'mailto') {
return;
}
event.preventDefault();
if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormRefresh') {
window.location.reload();
@ -38,27 +41,30 @@ export class HelpCameraSettingsScene extends Phaser.Scene {
}
});
if(!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video){
if(!localUserStore.getHelpCameraSettingsShown() && (!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video)){
this.openHelpCameraSettingsOpened();
localUserStore.setHelpCameraSettingsShown();
}
mediaManager.setHelpCameraSettingsCallBack(() => {
this.openHelpCameraSettingsOpened();
});
}
private openHelpCameraSettingsOpened(): void{
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
this.helpCameraSettingsOpened = true;
let middleY = (window.innerHeight / 3) - (495);
if(middleY < 0){
middleY = 0;
}
let middleX = (window.innerWidth / 3) - (370*0.85);
if(middleX < 0){
middleX = 0;
}
if(window.navigator.userAgent.includes('Firefox')){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
}else if(window.navigator.userAgent.includes('Chrome')){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
try{
if(window.navigator.userAgent.includes('Firefox')){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
}else if(window.navigator.userAgent.includes('Chrome')){
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
}
}catch(err) {
console.error('openHelpCameraSettingsOpened => getElementByIdOrFail => error', err);
}
const middleY = this.getMiddleY();
const middleX = this.getMiddleX();
this.tweens.add({
targets: this.helpCameraSettingsElement,
y: middleY,
@ -70,13 +76,15 @@ export class HelpCameraSettingsScene extends Phaser.Scene {
}
private closeHelpCameraSettingsOpened(): void{
const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement;
const middleX = this.getMiddleX();
/*const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement;
helpCameraSettingsInfo.innerText = '';
helpCameraSettingsInfo.style.display = 'none';
helpCameraSettingsInfo.style.display = 'none';*/
this.helpCameraSettingsOpened = false;
this.tweens.add({
targets: this.helpCameraSettingsElement,
y: -400,
y: -1000,
x: middleX,
duration: 1000,
ease: 'Power3',
overflow: 'scroll'
@ -91,5 +99,51 @@ export class HelpCameraSettingsScene extends Phaser.Scene {
}, 250);
}
update(time: number, delta: number): void {
if(this.helpCameraSettingsOpened){
const middleX = this.getMiddleX();
const middleY = this.getMiddleY();
this.tweens.add({
targets: this.helpCameraSettingsElement,
x: middleX,
y: middleY,
duration: 1000,
ease: 'Power3'
});
}
}
public onResize(ev: UIEvent): void {
const middleX = this.getMiddleX();
const middleY = this.getMiddleY();
this.tweens.add({
targets: this.helpCameraSettingsElement,
x: middleX,
y: middleY,
duration: 1000,
ease: 'Power3'
});
}
private getMiddleX() : number{
return (this.game.renderer.width / RESOLUTION) -
(
this.helpCameraSettingsElement
&& this.helpCameraSettingsElement.node
&& this.helpCameraSettingsElement.node.getBoundingClientRect().width > 0
? (this.helpCameraSettingsElement.node.getBoundingClientRect().width / 4)
: (400 / 2)
);
}
private getMiddleY() : number{
const middleY = ((window.innerHeight) - (
(this.helpCameraSettingsElement
&& this.helpCameraSettingsElement.node
&& this.helpCameraSettingsElement.node.getBoundingClientRect().height > 0
? this.helpCameraSettingsElement.node.getBoundingClientRect().height : 400 /*FIXME to use a const will be injected in HTMLElement*/)*2)) / 2;
return (middleY > 0 ? middleY / RESOLUTION : 0);
}
}

View file

@ -16,7 +16,7 @@ const gameMenuIconKey = 'gameMenuIcon';
const gameSettingsMenuKey = 'gameSettingsMenu';
const gameShare = 'gameShare';
const closedSideMenuX = -200;
const closedSideMenuX = -1000;
const openedSideMenuX = 0;
/**
@ -91,7 +91,7 @@ export class MenuScene extends Phaser.Scene {
this.menuElement.addListener('click');
this.menuElement.on('click', this.onMenuClick.bind(this));
worldFullWarningStream.stream.subscribe(() => this.showWorldCapacityWarning());
}
@ -118,7 +118,8 @@ export class MenuScene extends Phaser.Scene {
this.closeAll();
this.sideMenuOpened = true;
this.menuButton.getChildByID('openMenuButton').innerHTML = 'X';
if (gameManager.getCurrentGameScene(this).connection && gameManager.getCurrentGameScene(this).connection.isAdmin()) {
const connection = gameManager.getCurrentGameScene(this).connection;
if (connection && connection.isAdmin()) {
const adminSection = this.menuElement.getChildByID('adminConsoleSection') as HTMLElement;
adminSection.hidden = false;
}
@ -134,7 +135,7 @@ export class MenuScene extends Phaser.Scene {
ease: 'Power3'
});
}
private showWorldCapacityWarning() {
if (!this.warningContainer) {
this.warningContainer = new WarningContainer(this);
@ -147,7 +148,7 @@ export class MenuScene extends Phaser.Scene {
this.warningContainer = null
this.warningContainerTimeout = null
}, 120000);
}
private closeSideMenu(): void {

View file

@ -7,11 +7,11 @@ export const gameReportRessource = 'resources/html/gameReport.html';
export class ReportMenu extends Phaser.GameObjects.DOMElement {
private opened: boolean = false;
private userId!: number;
private userName!: string|undefined;
private anonymous: boolean;
constructor(scene: Phaser.Scene, anonymous: boolean) {
super(scene, -2000, -2000);
this.anonymous = anonymous;
@ -23,7 +23,7 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
const textToHide = this.getChildByID('askActionP') as HTMLElement;
textToHide.hidden = true;
}
scene.add.existing(this);
MenuScene.revealMenusAfterInit(this, gameReportKey);
@ -45,10 +45,10 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
this.close();
return;
}
this.userId = userId;
this.userName = userName;
const mainEl = this.getChildByID('gameReport') as HTMLElement;
this.x = this.getCenteredX(mainEl);
this.y = this.getHiddenY(mainEl);
@ -82,7 +82,7 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
ease: 'Power3'
});
}
//todo: into a parent class?
private getCenteredX(mainEl: HTMLElement): number {
return window.innerWidth / 4 - mainEl.clientWidth / 2;
@ -93,7 +93,7 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
private getCenteredY(mainEl: HTMLElement): number {
return window.innerHeight / 4 - mainEl.clientHeight / 2;
}
private toggleBlock(): void {
!blackListManager.isBlackListed(this.userId) ? blackListManager.blackList(this.userId) : blackListManager.cancelBlackList(this.userId);
this.close();
@ -109,10 +109,10 @@ export class ReportMenu extends Phaser.GameObjects.DOMElement {
gamePError.style.display = 'block';
return;
}
gameManager.getCurrentGameScene(this.scene).connection.emitReportPlayerMessage(
gameManager.getCurrentGameScene(this.scene).connection?.emitReportPlayerMessage(
this.userId,
gameTextArea.value
);
this.close();
}
}
}

View file

@ -52,7 +52,7 @@ export class ErrorScene extends Phaser.Scene {
this.subTitleField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height / 2 + 24, this.subTitle);
this.messageField = this.add.text(this.game.renderer.width / 2, this.game.renderer.height / 2 + 38, this.message, {
this.messageField = this.add.text(this.game.renderer.width / 2, this.game.renderer.height / 2 + 48, this.message, {
fontFamily: 'Georgia, "Goudy Bookletter 1911", Times, serif',
fontSize: '10px'
});