Merge branch 'metadataScriptingApi' of github.com:thecodingmachine/workadventure into metadataScriptAPIV2
This commit is contained in:
commit
24cc340cb9
194 changed files with 5470 additions and 4574 deletions
|
@ -28,13 +28,13 @@ export class MobileJoystick extends VirtualJoystick {
|
|||
this.visible = false;
|
||||
this.enable = false;
|
||||
|
||||
this.scene.input.on('pointerdown', (pointer: { x: number; y: number; wasTouch: boolean; event: TouchEvent }) => {
|
||||
this.scene.input.on('pointerdown', (pointer: Phaser.Input.Pointer) => {
|
||||
if (!pointer.wasTouch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's only display the joystick if there is one finger on the screen
|
||||
if (pointer.event.touches.length === 1) {
|
||||
if ((pointer.event as TouchEvent).touches.length === 1) {
|
||||
this.x = pointer.x;
|
||||
this.y = pointer.y;
|
||||
this.visible = true;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import type {IAnalyserNode, IAudioContext, IMediaStreamAudioSourceNode} from 'standardized-audio-context';
|
||||
|
||||
/**
|
||||
* Class to measure the sound volume of a media stream
|
||||
*/
|
||||
|
@ -5,10 +7,10 @@ export class SoundMeter {
|
|||
private instant: number;
|
||||
private clip: number;
|
||||
//private script: ScriptProcessorNode;
|
||||
private analyser: AnalyserNode|undefined;
|
||||
private analyser: IAnalyserNode<IAudioContext>|undefined;
|
||||
private dataArray: Uint8Array|undefined;
|
||||
private context: AudioContext|undefined;
|
||||
private source: MediaStreamAudioSourceNode|undefined;
|
||||
private context: IAudioContext|undefined;
|
||||
private source: IMediaStreamAudioSourceNode<IAudioContext>|undefined;
|
||||
|
||||
constructor() {
|
||||
this.instant = 0.0;
|
||||
|
@ -16,7 +18,7 @@ export class SoundMeter {
|
|||
//this.script = context.createScriptProcessor(2048, 1, 1);
|
||||
}
|
||||
|
||||
private init(context: AudioContext) {
|
||||
private init(context: IAudioContext) {
|
||||
this.context = context;
|
||||
this.analyser = this.context.createAnalyser();
|
||||
|
||||
|
@ -25,8 +27,12 @@ export class SoundMeter {
|
|||
this.dataArray = new Uint8Array(bufferLength);
|
||||
}
|
||||
|
||||
public connectToSource(stream: MediaStream, context: AudioContext): void
|
||||
public connectToSource(stream: MediaStream, context: IAudioContext): void
|
||||
{
|
||||
if (this.source !== undefined) {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
this.init(context);
|
||||
|
||||
this.source = this.context?.createMediaStreamSource(stream);
|
||||
|
@ -81,56 +87,3 @@ export class SoundMeter {
|
|||
|
||||
}
|
||||
|
||||
|
||||
// Meter class that generates a number correlated to audio volume.
|
||||
// The meter class itself displays nothing, but it makes the
|
||||
// instantaneous and time-decaying volumes available for inspection.
|
||||
// It also reports on the fraction of samples that were at or near
|
||||
// the top of the measurement range.
|
||||
/*function SoundMeter(context) {
|
||||
this.context = context;
|
||||
this.instant = 0.0;
|
||||
this.slow = 0.0;
|
||||
this.clip = 0.0;
|
||||
this.script = context.createScriptProcessor(2048, 1, 1);
|
||||
const that = this;
|
||||
this.script.onaudioprocess = function(event) {
|
||||
const input = event.inputBuffer.getChannelData(0);
|
||||
let i;
|
||||
let sum = 0.0;
|
||||
let clipcount = 0;
|
||||
for (i = 0; i < input.length; ++i) {
|
||||
sum += input[i] * input[i];
|
||||
if (Math.abs(input[i]) > 0.99) {
|
||||
clipcount += 1;
|
||||
}
|
||||
}
|
||||
that.instant = Math.sqrt(sum / input.length);
|
||||
that.slow = 0.95 * that.slow + 0.05 * that.instant;
|
||||
that.clip = clipcount / input.length;
|
||||
};
|
||||
}
|
||||
|
||||
SoundMeter.prototype.connectToSource = function(stream, callback) {
|
||||
console.log('SoundMeter connecting');
|
||||
try {
|
||||
this.mic = this.context.createMediaStreamSource(stream);
|
||||
this.mic.connect(this.script);
|
||||
// necessary to make sample run, but should not be.
|
||||
this.script.connect(this.context.destination);
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback(null);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundMeter.prototype.stop = function() {
|
||||
this.mic.disconnect();
|
||||
this.script.disconnect();
|
||||
};
|
||||
*/
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import Container = Phaser.GameObjects.Container;
|
||||
import type {Scene} from "phaser";
|
||||
import GameObject = Phaser.GameObjects.GameObject;
|
||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||
|
||||
|
||||
export class SoundMeterSprite extends Container {
|
||||
private rectangles: Rectangle[] = new Array<Rectangle>();
|
||||
private static readonly NB_BARS = 20;
|
||||
|
||||
constructor(scene: Scene, x?: number, y?: number, children?: GameObject[]) {
|
||||
super(scene, x, y, children);
|
||||
|
||||
for (let i = 0; i < SoundMeterSprite.NB_BARS; i++) {
|
||||
const rectangle = new Rectangle(scene, i * 13, 0, 10, 20, (Math.round(255 - i * 255 / SoundMeterSprite.NB_BARS) << 8) + (Math.round(i * 255 / SoundMeterSprite.NB_BARS) << 16));
|
||||
this.add(rectangle);
|
||||
this.rectangles.push(rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A number between 0 and 100
|
||||
*
|
||||
* @param volume
|
||||
*/
|
||||
public setVolume(volume: number): void {
|
||||
|
||||
const normalizedVolume = volume / 100 * SoundMeterSprite.NB_BARS;
|
||||
for (let i = 0; i < SoundMeterSprite.NB_BARS; i++) {
|
||||
if (normalizedVolume < i) {
|
||||
this.rectangles[i].alpha = 0.5;
|
||||
} else {
|
||||
this.rectangles[i].alpha = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getWidth(): number {
|
||||
return SoundMeterSprite.NB_BARS * 13;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import {PlayerAnimationDirections, PlayerAnimationTypes} from "../Player/Animation";
|
||||
import {SpeechBubble} from "./SpeechBubble";
|
||||
import BitmapText = Phaser.GameObjects.BitmapText;
|
||||
import Text = Phaser.GameObjects.Text;
|
||||
import Container = Phaser.GameObjects.Container;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import {TextureError} from "../../Exception/TextureError";
|
||||
|
@ -8,6 +8,7 @@ import {Companion} from "../Companion/Companion";
|
|||
import type {GameScene} from "../Game/GameScene";
|
||||
import {DEPTH_INGAME_TEXT_INDEX} from "../Game/DepthIndexes";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||
|
||||
const playerNameY = - 25;
|
||||
|
||||
|
@ -23,7 +24,7 @@ const interactiveRadius = 35;
|
|||
|
||||
export abstract class Character extends Container {
|
||||
private bubble: SpeechBubble|null = null;
|
||||
private readonly playerName: BitmapText;
|
||||
private readonly playerName: Text;
|
||||
public PlayerValue: string;
|
||||
public sprites: Map<string, Sprite>;
|
||||
private lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down;
|
||||
|
@ -32,6 +33,7 @@ export abstract class Character extends Container {
|
|||
public companion?: Companion;
|
||||
private emote: Phaser.GameObjects.Sprite | null = null;
|
||||
private emoteTween: Phaser.Tweens.Tween|null = null;
|
||||
scene: GameScene;
|
||||
|
||||
constructor(scene: GameScene,
|
||||
x: number,
|
||||
|
@ -41,10 +43,12 @@ export abstract class Character extends Container {
|
|||
direction: PlayerAnimationDirections,
|
||||
moving: boolean,
|
||||
frame: string | number,
|
||||
isClickable: boolean,
|
||||
companion: string|null,
|
||||
companionTexturePromise?: Promise<string>
|
||||
) {
|
||||
super(scene, x, y/*, texture, frame*/);
|
||||
this.scene = scene;
|
||||
this.PlayerValue = name;
|
||||
this.invisible = true
|
||||
|
||||
|
@ -56,16 +60,29 @@ export abstract class Character extends Container {
|
|||
this.invisible = false
|
||||
})
|
||||
|
||||
this.playerName = new BitmapText(scene, 0, playerNameY, 'main_font', name, 7);
|
||||
this.playerName.setOrigin(0.5).setCenterAlign().setDepth(DEPTH_INGAME_TEXT_INDEX);
|
||||
this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "gray"});
|
||||
this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
||||
this.add(this.playerName);
|
||||
|
||||
if (this.isClickable()) {
|
||||
if (isClickable) {
|
||||
this.setInteractive({
|
||||
hitArea: new Phaser.Geom.Circle(0, 0, interactiveRadius),
|
||||
hitAreaCallback: Phaser.Geom.Circle.Contains, //eslint-disable-line @typescript-eslint/unbound-method
|
||||
useHandCursor: true,
|
||||
});
|
||||
|
||||
this.on('pointerover',() => {
|
||||
this.getOutlinePlugin()?.add(this.playerName, {
|
||||
thickness: 2,
|
||||
outlineColor: 0xffff00
|
||||
});
|
||||
this.scene.markDirty();
|
||||
});
|
||||
this.on('pointerout',() => {
|
||||
this.getOutlinePlugin()?.remove(this.playerName);
|
||||
this.scene.markDirty();
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
scene.add.existing(this);
|
||||
|
@ -79,23 +96,25 @@ export abstract class Character extends Container {
|
|||
this.setDepth(-1);
|
||||
|
||||
this.playAnimation(direction, moving);
|
||||
|
||||
|
||||
if (typeof companion === 'string') {
|
||||
this.addCompanion(companion, companionTexturePromise);
|
||||
}
|
||||
}
|
||||
|
||||
private getOutlinePlugin(): OutlinePipelinePlugin|undefined {
|
||||
return this.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined;
|
||||
}
|
||||
|
||||
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
||||
if (typeof texturePromise !== 'undefined') {
|
||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract isClickable(): boolean;
|
||||
|
||||
public addTextures(textures: string[], frame?: string | number): void {
|
||||
for (const texture of textures) {
|
||||
if(!this.scene.textures.exists(texture)){
|
||||
if(this.scene && !this.scene.textures.exists(texture)){
|
||||
throw new TextureError('texture not found');
|
||||
}
|
||||
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
||||
|
@ -240,28 +259,28 @@ export abstract class Character extends Container {
|
|||
this.scene.sys.updateList.remove(sprite);
|
||||
}
|
||||
}
|
||||
this.list.forEach(objectContaining => objectContaining.destroy())
|
||||
this.list.forEach(objectContaining => objectContaining.destroy())
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
|
||||
playEmote(emoteKey: string) {
|
||||
this.cancelPreviousEmote();
|
||||
|
||||
const scalingFactor = waScaleManager.uiScalingFactor * 0.05;
|
||||
const emoteY = -30 - scalingFactor * 10;
|
||||
|
||||
|
||||
this.playerName.setVisible(false);
|
||||
this.emote = new Sprite(this.scene, 0, 0, emoteKey);
|
||||
this.emote.setAlpha(0);
|
||||
this.emote.setScale(0.1 * scalingFactor);
|
||||
this.add(this.emote);
|
||||
this.scene.sys.updateList.add(this.emote);
|
||||
|
||||
|
||||
this.createStartTransition(scalingFactor, emoteY);
|
||||
}
|
||||
|
||||
private createStartTransition(scalingFactor: number, emoteY: number) {
|
||||
this.emoteTween = this.scene.tweens.add({
|
||||
this.emoteTween = this.scene?.tweens.add({
|
||||
targets: this.emote,
|
||||
props: {
|
||||
scale: scalingFactor,
|
||||
|
@ -277,7 +296,7 @@ export abstract class Character extends Container {
|
|||
}
|
||||
|
||||
private startPulseTransition(emoteY: number, scalingFactor: number) {
|
||||
this.emoteTween = this.scene.tweens.add({
|
||||
this.emoteTween = this.scene?.tweens.add({
|
||||
targets: this.emote,
|
||||
props: {
|
||||
y: emoteY * 1.3,
|
||||
|
@ -294,7 +313,7 @@ export abstract class Character extends Container {
|
|||
}
|
||||
|
||||
private startExitTransition(emoteY: number) {
|
||||
this.emoteTween = this.scene.tweens.add({
|
||||
this.emoteTween = this.scene?.tweens.add({
|
||||
targets: this.emote,
|
||||
props: {
|
||||
alpha: 0,
|
||||
|
|
20
front/src/Phaser/Entity/CustomizedCharacter.ts
Normal file
20
front/src/Phaser/Entity/CustomizedCharacter.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Container = Phaser.GameObjects.Container;
|
||||
import type {Scene} from "phaser";
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
|
||||
/**
|
||||
* A sprite of a customized character (used in the Customize Scene only)
|
||||
*/
|
||||
export class CustomizedCharacter extends Container {
|
||||
public constructor(scene: Scene, x: number, y: number, layers: string[]) {
|
||||
super(scene, x, y);
|
||||
this.updateSprites(layers);
|
||||
}
|
||||
|
||||
public updateSprites(layers: string[]): void {
|
||||
this.removeAll(true);
|
||||
for (const layer of layers) {
|
||||
this.add(new Sprite(this.scene, 0, 0, layer));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,12 +2,15 @@ import type {GameScene} from "../Game/GameScene";
|
|||
import type {PointInterface} from "../../Connexion/ConnexionModels";
|
||||
import {Character} from "../Entity/Character";
|
||||
import type {PlayerAnimationDirections} from "../Player/Animation";
|
||||
import {requestVisitCardsStore} from "../../Stores/GameStore";
|
||||
|
||||
|
||||
/**
|
||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||
*/
|
||||
export class RemotePlayer extends Character {
|
||||
userId: number;
|
||||
private visitCardUrl: string|null;
|
||||
|
||||
constructor(
|
||||
userId: number,
|
||||
|
@ -18,13 +21,19 @@ export class RemotePlayer extends Character {
|
|||
texturesPromise: Promise<string[]>,
|
||||
direction: PlayerAnimationDirections,
|
||||
moving: boolean,
|
||||
visitCardUrl: string|null,
|
||||
companion: string|null,
|
||||
companionTexturePromise?: Promise<string>
|
||||
) {
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, companion, companionTexturePromise);
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, !!visitCardUrl, companion, companionTexturePromise);
|
||||
|
||||
//set data
|
||||
this.userId = userId;
|
||||
this.visitCardUrl = visitCardUrl;
|
||||
|
||||
this.on('pointerdown', () => {
|
||||
requestVisitCardsStore.set(this.visitCardUrl);
|
||||
})
|
||||
}
|
||||
|
||||
updatePosition(position: PointInterface): void {
|
||||
|
@ -38,8 +47,4 @@ export class RemotePlayer extends Character {
|
|||
this.companion.setTarget(position.x, position.y, position.direction as PlayerAnimationDirections);
|
||||
}
|
||||
}
|
||||
|
||||
isClickable(): boolean {
|
||||
return false; //todo: make remote players clickable if they are logged in.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ export interface AddPlayerInterface {
|
|||
name: string;
|
||||
characterLayers: BodyResourceDescriptionInterface[];
|
||||
position: PointInterface;
|
||||
visitCardUrl: string|null;
|
||||
companion: string|null;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,11 @@ export abstract class DirtyScene extends ResizableScene {
|
|||
return this.dirty || this.objectListChanged;
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
public markDirty(): void {
|
||||
this.events.once(Phaser.Scenes.Events.POST_UPDATE, () => this.dirty = true);
|
||||
}
|
||||
|
||||
public onResize(): void {
|
||||
this.objectListChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,22 @@ export class Game extends Phaser.Game {
|
|||
constructor(GameConfig: Phaser.Types.Core.GameConfig) {
|
||||
super(GameConfig);
|
||||
|
||||
window.addEventListener('resize', (event) => {
|
||||
this.scale.on(Phaser.Scale.Events.RESIZE, () => {
|
||||
for (const scene of this.scene.getScenes(true)) {
|
||||
if (scene instanceof ResizableScene) {
|
||||
scene.onResize();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*window.addEventListener('resize', (event) => {
|
||||
// Let's trigger the onResize method of any active scene that is a ResizableScene
|
||||
for (const scene of this.scene.getScenes(true)) {
|
||||
if (scene instanceof ResizableScene) {
|
||||
scene.onResize(event);
|
||||
}
|
||||
}
|
||||
});
|
||||
});*/
|
||||
}
|
||||
|
||||
public step(time: number, delta: number)
|
||||
|
|
|
@ -2,11 +2,13 @@ import {GameScene} from "./GameScene";
|
|||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||
import type {Room} from "../../Connexion/Room";
|
||||
import {MenuScene, MenuSceneName} from "../Menu/MenuScene";
|
||||
import {HelpCameraSettingsScene, HelpCameraSettingsSceneName} from "../Menu/HelpCameraSettingsScene";
|
||||
import {LoginSceneName} from "../Login/LoginScene";
|
||||
import {SelectCharacterSceneName} from "../Login/SelectCharacterScene";
|
||||
import {EnableCameraSceneName} from "../Login/EnableCameraScene";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {get} from "svelte/store";
|
||||
import {requestedCameraState, requestedMicrophoneState} from "../../Stores/MediaStore";
|
||||
import {helpCameraSettingsVisibleStore} from "../../Stores/HelpCameraSettingsStore";
|
||||
|
||||
|
||||
|
||||
|
@ -71,11 +73,11 @@ export class GameManager {
|
|||
|
||||
public async loadMap(room: Room, scenePlugin: Phaser.Scenes.ScenePlugin): Promise<void> {
|
||||
const roomID = room.id;
|
||||
const mapUrl = await room.getMapUrl();
|
||||
const mapDetail = await room.getMapDetail();
|
||||
|
||||
const gameIndex = scenePlugin.getIndex(roomID);
|
||||
if(gameIndex === -1){
|
||||
const game : Phaser.Scene = new GameScene(room, mapUrl);
|
||||
const game : Phaser.Scene = new GameScene(room, mapDetail.mapUrl);
|
||||
scenePlugin.add(roomID, game, false);
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +86,11 @@ export class GameManager {
|
|||
console.log('starting '+ (this.currentGameSceneName || this.startRoom.id))
|
||||
scenePlugin.start(this.currentGameSceneName || this.startRoom.id);
|
||||
scenePlugin.launch(MenuSceneName);
|
||||
scenePlugin.launch(HelpCameraSettingsSceneName);//700
|
||||
|
||||
if(!localUserStore.getHelpCameraSettingsShown() && (!get(requestedMicrophoneState) || !get(requestedCameraState))){
|
||||
helpCameraSettingsVisibleStore.set(true);
|
||||
localUserStore.setHelpCameraSettingsShown();
|
||||
}
|
||||
}
|
||||
|
||||
public gameSceneIsCreated(scene: GameScene) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type {ITiledMap, ITiledMapLayer, ITiledMapTileLayer} from "../Map/ITiledMap";
|
||||
import type {ITiledMap, ITiledMapLayer, ITiledMapLayerProperty} from "../Map/ITiledMap";
|
||||
import { flattenGroupLayersMap } from "../Map/LayersFlattener";
|
||||
import TilemapLayer = Phaser.Tilemaps.TilemapLayer;
|
||||
import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes";
|
||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||
|
||||
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void;
|
||||
|
||||
|
@ -10,12 +10,16 @@ export type PropertyChangeCallback = (newValue: string | number | boolean | unde
|
|||
* It is used to handle layer properties.
|
||||
*/
|
||||
export class GameMap {
|
||||
private key: number|undefined;
|
||||
private lastProperties = new Map<string, string|boolean|number>();
|
||||
private key: number | undefined;
|
||||
private lastProperties = new Map<string, string | boolean | number>();
|
||||
private callbacks = new Map<string, Array<PropertyChangeCallback>>();
|
||||
|
||||
private tileSetPropertyMap: { [tile_index: number]: Array<ITiledMapLayerProperty> } = {}
|
||||
public readonly flatLayers: ITiledMapLayer[];
|
||||
public readonly phaserLayers: TilemapLayer[] = [];
|
||||
|
||||
public exitUrls: Array<string> = []
|
||||
|
||||
public constructor(private map: ITiledMap, phaserMap: Phaser.Tilemaps.Tilemap, terrains: Array<Phaser.Tilemaps.Tileset>) {
|
||||
this.flatLayers = flattenGroupLayersMap(map);
|
||||
let depth = -2;
|
||||
|
@ -27,8 +31,22 @@ export class GameMap {
|
|||
depth = DEPTH_OVERLAY_INDEX;
|
||||
}
|
||||
}
|
||||
for (const tileset of map.tilesets) {
|
||||
tileset?.tiles?.forEach(tile => {
|
||||
if (tile.properties) {
|
||||
this.tileSetPropertyMap[tileset.firstgid + tile.id] = tile.properties
|
||||
tile.properties.forEach(prop => {
|
||||
if (prop.name == "exitUrl" && typeof prop.value == "string") {
|
||||
this.exitUrls.push(prop.value);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the position of the current player (in pixels)
|
||||
* This will trigger events if properties are changing.
|
||||
|
@ -63,21 +81,27 @@ export class GameMap {
|
|||
}
|
||||
}
|
||||
|
||||
public getCurrentProperties(): Map<string, string|boolean|number> {
|
||||
public getCurrentProperties(): Map<string, string | boolean | number> {
|
||||
return this.lastProperties;
|
||||
}
|
||||
|
||||
private getProperties(key: number): Map<string, string|boolean|number> {
|
||||
const properties = new Map<string, string|boolean|number>();
|
||||
private getProperties(key: number): Map<string, string | boolean | number> {
|
||||
const properties = new Map<string, string | boolean | number>();
|
||||
|
||||
for (const layer of this.flatLayers) {
|
||||
if (layer.type !== 'tilelayer') {
|
||||
continue;
|
||||
}
|
||||
const tiles = layer.data as number[];
|
||||
if (tiles[key] == 0) {
|
||||
continue;
|
||||
|
||||
let tileIndex: number | undefined = undefined;
|
||||
if (layer.data) {
|
||||
const tiles = layer.data as number[];
|
||||
if (tiles[key] == 0) {
|
||||
continue;
|
||||
}
|
||||
tileIndex = tiles[key]
|
||||
}
|
||||
|
||||
// There is a tile in this layer, let's embed the properties
|
||||
if (layer.properties !== undefined) {
|
||||
for (const layerProperty of layer.properties) {
|
||||
|
@ -87,6 +111,16 @@ export class GameMap {
|
|||
properties.set(layerProperty.name, layerProperty.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (tileIndex) {
|
||||
this.tileSetPropertyMap[tileIndex]?.forEach(property => {
|
||||
if (property.value) {
|
||||
properties.set(property.name, property.value)
|
||||
} else if (properties.has(property.name)) {
|
||||
properties.delete(property.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
@ -118,11 +152,11 @@ export class GameMap {
|
|||
}
|
||||
|
||||
public findLayer(layerName: string): ITiledMapLayer | undefined {
|
||||
return this.flatLayers.find((layer) => layer.name = layerName);
|
||||
return this.flatLayers.find((layer) => layer.name === layerName);
|
||||
}
|
||||
|
||||
public findPhaserLayer(layerName: string): TilemapLayer | undefined {
|
||||
return this.phaserLayers.find((layer) => layer.layer.name = layerName);
|
||||
return this.phaserLayers.find((layer) => layer.layer.name === layerName);
|
||||
}
|
||||
|
||||
public addTerrain(terrain : Phaser.Tilemaps.Tileset): void {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import {gameManager} from "./GameManager";
|
||||
import { Queue } from 'queue-typescript';
|
||||
import type { Subscription } from "rxjs";
|
||||
import { GlobalMessageManager } from "../../Administration/GlobalMessageManager";
|
||||
import { userMessageManager } from "../../Administration/UserMessageManager";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||
import type {
|
||||
GroupCreatedUpdatedMessageInterface,
|
||||
MessageUserJoined,
|
||||
|
@ -9,72 +14,73 @@ import type {
|
|||
PositionInterface,
|
||||
RoomJoinedMessageInterface
|
||||
} from "../../Connexion/ConnexionModels";
|
||||
import { hasMovedEventName, Player , requestEmoteEventName} from "../Player/Player";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { Room } from "../../Connexion/Room";
|
||||
import type { RoomConnection } from "../../Connexion/RoomConnection";
|
||||
import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream";
|
||||
import {
|
||||
DEBUG_MODE,
|
||||
JITSI_PRIVATE_MODE,
|
||||
MAX_PER_GROUP,
|
||||
POSITION_DELAY,
|
||||
POSITION_DELAY
|
||||
} from "../../Enum/EnvironmentVariable";
|
||||
import type {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapLayerProperty,
|
||||
ITiledMapObject,
|
||||
ITiledText,
|
||||
ITiledMapTileLayer,
|
||||
ITiledTileSet
|
||||
} from "../Map/ITiledMap";
|
||||
import type { AddPlayerInterface } from "./AddPlayerInterface";
|
||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||
import { PlayerMovement } from "./PlayerMovement";
|
||||
import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator";
|
||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||
import { Queue } from 'queue-typescript';
|
||||
import { SimplePeer, UserSimplePeerInterface } from "../../WebRtc/SimplePeer";
|
||||
import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene";
|
||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { TextureError } from "../../Exception/TextureError";
|
||||
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
|
||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||
import { peerStore } from "../../Stores/PeerStore";
|
||||
import { touchScreenManager } from "../../Touch/TouchScreenManager";
|
||||
import { urlManager } from "../../Url/UrlManager";
|
||||
import { audioManager } from "../../WebRtc/AudioManager";
|
||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||
import {
|
||||
CenterListener,
|
||||
AUDIO_LOOP_PROPERTY, AUDIO_VOLUME_PROPERTY, CenterListener,
|
||||
JITSI_MESSAGE_PROPERTIES,
|
||||
layoutManager,
|
||||
LayoutMode,
|
||||
ON_ACTION_TRIGGER_BUTTON,
|
||||
TRIGGER_JITSI_PROPERTIES,
|
||||
TRIGGER_WEBSITE_PROPERTIES,
|
||||
WEBSITE_MESSAGE_PROPERTIES,
|
||||
AUDIO_VOLUME_PROPERTY,
|
||||
AUDIO_LOOP_PROPERTY
|
||||
WEBSITE_MESSAGE_PROPERTIES
|
||||
} from "../../WebRtc/LayoutManager";
|
||||
import { GameMap } from "./GameMap";
|
||||
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
|
||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
||||
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
|
||||
import type { ActionableItem } from "../Items/ActionableItem";
|
||||
import { UserInputManager } from "../UserInput/UserInputManager";
|
||||
import {soundManager} from "./SoundManager";
|
||||
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
|
||||
import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils";
|
||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||
import type { RoomConnection } from "../../Connexion/RoomConnection";
|
||||
import { GlobalMessageManager } from "../../Administration/GlobalMessageManager";
|
||||
import { userMessageManager } from "../../Administration/UserMessageManager";
|
||||
import { ConsoleGlobalMessageManager } from "../../Administration/ConsoleGlobalMessageManager";
|
||||
import { ResizableScene } from "../Login/ResizableScene";
|
||||
import { Room } from "../../Connexion/Room";
|
||||
import { jitsiFactory } from "../../WebRtc/JitsiFactory";
|
||||
import { urlManager } from "../../Url/UrlManager";
|
||||
import { audioManager } from "../../WebRtc/AudioManager";
|
||||
import { PresentationModeIcon } from "../Components/PresentationModeIcon";
|
||||
import { SimplePeer, UserSimplePeerInterface } from "../../WebRtc/SimplePeer";
|
||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||
import { ChatModeIcon } from "../Components/ChatModeIcon";
|
||||
import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon";
|
||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import { TextureError } from "../../Exception/TextureError";
|
||||
import { addLoader } from "../Components/Loader";
|
||||
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
|
||||
import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon";
|
||||
import { PresentationModeIcon } from "../Components/PresentationModeIcon";
|
||||
import { TextUtils } from "../Components/TextUtils";
|
||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||
import type { ActionableItem } from "../Items/ActionableItem";
|
||||
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
|
||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import type {
|
||||
ITiledMap,
|
||||
ITiledMapLayer,
|
||||
ITiledMapLayerProperty,
|
||||
ITiledMapObject,
|
||||
ITiledMapTileLayer,
|
||||
ITiledTileSet } from "../Map/ITiledMap";
|
||||
import { MenuScene, MenuSceneName } from '../Menu/MenuScene';
|
||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||
import { ErrorSceneName } from "../Reconnecting/ErrorScene";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene";
|
||||
import { waScaleManager } from "../Services/WaScaleManager";
|
||||
import { PinchManager } from "../UserInput/PinchManager";
|
||||
import { UserInputManager } from "../UserInput/UserInputManager";
|
||||
import type { AddPlayerInterface } from "./AddPlayerInterface";
|
||||
import { DEPTH_OVERLAY_INDEX } from "./DepthIndexes";
|
||||
import { DirtyScene } from "./DirtyScene";
|
||||
import { EmoteManager } from "./EmoteManager";
|
||||
import { gameManager } from "./GameManager";
|
||||
import { GameMap } from "./GameMap";
|
||||
import { PlayerMovement } from "./PlayerMovement";
|
||||
import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator";
|
||||
import Texture = Phaser.Textures.Texture;
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||
|
@ -82,22 +88,12 @@ import GameObject = Phaser.GameObjects.GameObject;
|
|||
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
|
||||
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||
import EVENT_TYPE = Phaser.Scenes.Events
|
||||
import type { Subscription } from "rxjs";
|
||||
import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream";
|
||||
import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager";
|
||||
import RenderTexture = Phaser.GameObjects.RenderTexture;
|
||||
import Tilemap = Phaser.Tilemaps.Tilemap;
|
||||
import {DirtyScene} from "./DirtyScene";
|
||||
import {TextUtils} from "../Components/TextUtils";
|
||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {PinchManager} from "../UserInput/PinchManager";
|
||||
import {joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey} from "../Components/MobileJoystick";
|
||||
import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {peerStore} from "../../Stores/PeerStore";
|
||||
import {EmoteManager} from "./EmoteManager";
|
||||
import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent';
|
||||
import { MenuScene, MenuSceneName } from '../Menu/MenuScene';
|
||||
|
||||
import AnimatedTiles from "phaser-animated-tiles";
|
||||
import {soundManager} from "./SoundManager";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface | null,
|
||||
|
@ -144,6 +140,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
Map!: Phaser.Tilemaps.Tilemap;
|
||||
Objects!: Array<Phaser.Physics.Arcade.Sprite>;
|
||||
mapFile!: ITiledMap;
|
||||
animatedTiles!: AnimatedTiles;
|
||||
groups: Map<number, Sprite>;
|
||||
startX!: number;
|
||||
startY!: number;
|
||||
|
@ -155,13 +152,13 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
public connection: RoomConnection | undefined;
|
||||
private simplePeer!: SimplePeer;
|
||||
private GlobalMessageManager!: GlobalMessageManager;
|
||||
public ConsoleGlobalMessageManager!: ConsoleGlobalMessageManager;
|
||||
private connectionAnswerPromise: Promise<RoomJoinedMessageInterface>;
|
||||
private connectionAnswerPromiseResolve!: (value: RoomJoinedMessageInterface | PromiseLike<RoomJoinedMessageInterface>) => void;
|
||||
// A promise that will resolve when the "create" method is called (signaling loading is ended)
|
||||
private createPromise: Promise<void>;
|
||||
private createPromiseResolve!: (value?: void | PromiseLike<void>) => void;
|
||||
private iframeSubscriptionList!: Array<Subscription>;
|
||||
private peerStoreUnsubscribe!: () => void;
|
||||
MapUrlFile: string;
|
||||
RoomId: string;
|
||||
instance: string;
|
||||
|
@ -230,11 +227,11 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
this.load.image(joystickBaseKey, joystickBaseImg);
|
||||
this.load.image(joystickThumbKey, joystickThumbImg);
|
||||
}
|
||||
//todo: in an emote manager.
|
||||
this.load.spritesheet('emote-music', 'resources/emotes/pipo-popupemotes005.png', {
|
||||
frameHeight: 32,
|
||||
frameWidth: 32,
|
||||
});
|
||||
this.load.audio('audio-webrtc-in', '/resources/objects/webrtc-in.mp3');
|
||||
this.load.audio('audio-webrtc-out', '/resources/objects/webrtc-out.mp3');
|
||||
//this.load.audio('audio-report-message', '/resources/objects/report-message.mp3');
|
||||
this.sound.pauseOnBlur = false;
|
||||
|
||||
this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => {
|
||||
// If we happen to be in HTTP and we are trying to load a URL in HTTPS only... (this happens only in dev environments)
|
||||
if (window.location.protocol === 'http:' && file.src === this.MapUrlFile && file.src.startsWith('http:') && this.originalMapUrl === undefined) {
|
||||
|
@ -267,6 +264,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
message: this.originalMapUrl ?? file.src
|
||||
});
|
||||
});
|
||||
this.load.scenePlugin('AnimatedTiles', AnimatedTiles, 'animatedTiles', 'animatedTiles');
|
||||
this.load.on('filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => {
|
||||
this.onMapLoad(data);
|
||||
});
|
||||
|
@ -281,6 +279,14 @@ export class GameScene extends DirtyScene 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');
|
||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(this.load as any).rexWebFont({
|
||||
custom: {
|
||||
families: ['Press Start 2P'],
|
||||
urls: ['/resources/fonts/fonts.css'],
|
||||
testString: 'abcdefg'
|
||||
},
|
||||
});
|
||||
|
||||
//this function must stay at the end of preload function
|
||||
addLoader(this);
|
||||
|
@ -435,6 +441,10 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
}
|
||||
}
|
||||
|
||||
this.gameMap.exitUrls.forEach(exitUrl => {
|
||||
this.loadNextGame(exitUrl)
|
||||
})
|
||||
|
||||
this.initStartXAndStartY();
|
||||
|
||||
//add entities
|
||||
|
@ -458,6 +468,9 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
|
||||
this.initCamera();
|
||||
|
||||
this.animatedTiles.init(this.Map);
|
||||
this.events.on('tileanimationupdate', () => this.dirty = true);
|
||||
|
||||
this.initCirclesCanvas();
|
||||
|
||||
// Let's pause the scene if the connection is not established yet
|
||||
|
@ -509,6 +522,21 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
}
|
||||
|
||||
this.emoteManager = new EmoteManager(this);
|
||||
|
||||
let oldPeerNumber = 0;
|
||||
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
|
||||
const newPeerNumber = peers.size;
|
||||
if (newPeerNumber > oldPeerNumber) {
|
||||
this.sound.play('audio-webrtc-in', {
|
||||
volume: 0.2
|
||||
});
|
||||
} else if (newPeerNumber < oldPeerNumber) {
|
||||
this.sound.play('audio-webrtc-out', {
|
||||
volume: 0.2
|
||||
});
|
||||
}
|
||||
oldPeerNumber = newPeerNumber;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -541,6 +569,7 @@ export class GameScene extends DirtyScene implements CenterListener {
|
|||
characterLayers: message.characterLayers,
|
||||
name: message.name,
|
||||
position: message.position,
|
||||
visitCardUrl: message.visitCardUrl,
|
||||
companion: message.companion
|
||||
}
|
||||
this.addPlayer(userMessage);
|
||||
|
@ -645,7 +674,6 @@ export class GameScene extends DirtyScene 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.isAdmin());
|
||||
|
||||
|
||||
this.scene.wake();
|
||||
|
@ -868,49 +896,31 @@ ${escapedMessage}
|
|||
this.userInputManager.disableControls();
|
||||
}));
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent)=>
|
||||
{
|
||||
const url = new URL(playSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.playSound(this.load,this.sound,url.toString(),playSoundEvent.config);
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.stopSoundStream.subscribe((stopSoundEvent)=>
|
||||
{
|
||||
const url = new URL(stopSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.stopSound(this.sound,url.toString());
|
||||
this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent) => {
|
||||
const url = new URL(playSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.playSound(this.load, this.sound, url.toString(), playSoundEvent.config);
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.loadSoundStream.subscribe((loadSoundEvent)=>
|
||||
{
|
||||
this.iframeSubscriptionList.push(iframeListener.stopSoundStream.subscribe((stopSoundEvent) => {
|
||||
const url = new URL(stopSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.stopSound(this.sound, url.toString());
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.loadSoundStream.subscribe((loadSoundEvent) => {
|
||||
const url = new URL(loadSoundEvent.url, this.MapUrlFile);
|
||||
soundManager.loadSound(this.load,this.sound,url.toString());
|
||||
soundManager.loadSound(this.load, this.sound, url.toString());
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{
|
||||
this.userInputManager.restoreControls();
|
||||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.changeTileStream.subscribe(event => {
|
||||
for (const eventTile of event) {
|
||||
const layer = this.gameMap.findPhaserLayer(eventTile.layer);
|
||||
if (layer) {
|
||||
console.log('layer : ', layer);
|
||||
const tile = layer.getTileAt(eventTile.x, eventTile.y, true)
|
||||
if (typeof eventTile.tile == "string") {
|
||||
const tileIndex = this.getIndexForTileType(eventTile.tile);
|
||||
if (tileIndex) {
|
||||
tile.index = tileIndex
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
tile.index = eventTile.tile //+ firsrtgid du layer
|
||||
}
|
||||
}
|
||||
}
|
||||
//this.dirty = true;
|
||||
}))
|
||||
|
||||
}));
|
||||
this.iframeSubscriptionList.push(iframeListener.loadPageStream.subscribe((url: string) => {
|
||||
this.loadNextGame(url).then(() => {
|
||||
this.events.once(EVENT_TYPE.POST_UPDATE, () => {
|
||||
this.onMapExit(url);
|
||||
})
|
||||
})
|
||||
}));
|
||||
let scriptedBubbleSprite: Sprite;
|
||||
this.iframeSubscriptionList.push(iframeListener.displayBubbleStream.subscribe(() => {
|
||||
scriptedBubbleSprite = new Sprite(this, this.CurrentPlayer.x + 25, this.CurrentPlayer.y, 'circleSprite-white');
|
||||
|
@ -939,23 +949,16 @@ ${escapedMessage}
|
|||
}))
|
||||
|
||||
this.iframeSubscriptionList.push(iframeListener.gameStateStream.subscribe(() => {
|
||||
iframeListener.sendFrozenGameStateEvent({
|
||||
iframeListener.sendGameStateEvent({
|
||||
mapUrl: this.MapUrlFile,
|
||||
startLayerName: this.startLayerName,
|
||||
uuid: localUserStore.getLocalUser()?.uuid,
|
||||
nickname: localUserStore.getName(),
|
||||
roomId: this.RoomId,
|
||||
tags: this.connection ? this.connection.getAllTag() : []
|
||||
tags: this.connection ? this.connection.getAllTags() : []
|
||||
})
|
||||
}));
|
||||
|
||||
/* this.iframeSubscriptionList.push(iframeListener.tilesetLoaderStream.subscribe((tileset) => {
|
||||
//this.load.tilemapTiledJSON('logo', tileset.imgUrl);
|
||||
this.load.image('logo', tileset.imgUrl);
|
||||
this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.imgUrl, tileset.tilewidth, tileset.tileheight, tileset.margin, tileset.spacing));
|
||||
this.gameMap.addTerrain(this.Terrains[this.Terrains.length - 1]);
|
||||
}))*/
|
||||
|
||||
}
|
||||
|
||||
private setPropertyLayer(layerName: string, propertyName: string, propertyValue: string | number | boolean | undefined): void {
|
||||
|
@ -1045,6 +1048,9 @@ ${escapedMessage}
|
|||
this.userInputManager.destroy();
|
||||
this.pinchManager?.destroy();
|
||||
this.emoteManager.destroy();
|
||||
this.peerStoreUnsubscribe();
|
||||
|
||||
mediaManager.hideGameOverlay();
|
||||
|
||||
for (const iframeEvents of this.iframeSubscriptionList) {
|
||||
iframeEvents.unsubscribe();
|
||||
|
@ -1156,10 +1162,10 @@ ${escapedMessage}
|
|||
}
|
||||
|
||||
//todo: push that into the gameManager
|
||||
private loadNextGame(exitSceneIdentifier: string) : void{
|
||||
private loadNextGame(exitSceneIdentifier: string) : Promise<void>{
|
||||
const { roomId, hash } = Room.getIdFromIdentifier(exitSceneIdentifier, this.MapUrlFile, this.instance);
|
||||
const room = new Room(roomId);
|
||||
gameManager.loadMap(room, this.scene).catch(() => {});
|
||||
return gameManager.loadMap(room, this.scene).catch(() => { });
|
||||
}
|
||||
|
||||
private startUser(layer: ITiledMapTileLayer): PositionInterface {
|
||||
|
@ -1233,7 +1239,10 @@ ${escapedMessage}
|
|||
this.companion,
|
||||
this.companion !== null ? lazyLoadCompanionResource(this.load, this.companion) : undefined
|
||||
);
|
||||
this.CurrentPlayer.on('pointerdown', () => {
|
||||
this.CurrentPlayer.on('pointerdown', (pointer: Phaser.Input.Pointer) => {
|
||||
if (pointer.wasTouch && (pointer.event as TouchEvent).touches.length > 1) {
|
||||
return; //we don't want the menu to open when pinching on a touch screen.
|
||||
}
|
||||
this.emoteManager.getMenuImages().then((emoteMenuElements) => this.CurrentPlayer.openOrCloseEmoteMenu(emoteMenuElements))
|
||||
})
|
||||
this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => {
|
||||
|
@ -1433,6 +1442,7 @@ ${escapedMessage}
|
|||
texturesPromise,
|
||||
addPlayerData.position.direction as PlayerAnimationDirections,
|
||||
addPlayerData.position.moving,
|
||||
addPlayerData.visitCardUrl,
|
||||
addPlayerData.companion,
|
||||
addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined
|
||||
);
|
||||
|
@ -1539,8 +1549,8 @@ ${escapedMessage}
|
|||
this.connection?.emitActionableEvent(itemId, eventName, state, parameters);
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
super.onResize(ev);
|
||||
public onResize(): void {
|
||||
super.onResize();
|
||||
this.reposition();
|
||||
|
||||
// Send new viewport to server
|
||||
|
|
|
@ -17,7 +17,9 @@ class SoundManager {
|
|||
return res(sound);
|
||||
}
|
||||
loadPlugin.audio(soundUrl, soundUrl);
|
||||
loadPlugin.once('filecomplete-audio-' + soundUrl, () => res(soundManager.add(soundUrl)));
|
||||
loadPlugin.once('filecomplete-audio-' + soundUrl, () => {
|
||||
res(soundManager.add(soundUrl));
|
||||
});
|
||||
loadPlugin.start();
|
||||
});
|
||||
this.soundPromises.set(soundUrl,soundPromise);
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* It has coordinates and an "activation radius"
|
||||
*/
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import {OutlinePipeline} from "../Shaders/OutlinePipeline";
|
||||
import type {GameScene} from "../Game/GameScene";
|
||||
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||
|
||||
type EventCallback = (state: unknown, parameters: unknown) => void;
|
||||
|
||||
|
@ -42,11 +42,11 @@ export class ActionableItem {
|
|||
return;
|
||||
}
|
||||
this.isSelectable = true;
|
||||
if (this.sprite.pipeline) {
|
||||
// Commented out to try to fix MacOS issue
|
||||
/*this.sprite.setPipeline(OutlinePipeline.KEY);
|
||||
this.sprite.pipeline.set2f('uTextureSize', this.sprite.texture.getSourceImage().width, this.sprite.texture.getSourceImage().height);*/
|
||||
}
|
||||
|
||||
this.getOutlinePlugin()?.add(this.sprite, {
|
||||
thickness: 2,
|
||||
outlineColor: 0xffff00
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,8 +57,11 @@ export class ActionableItem {
|
|||
return;
|
||||
}
|
||||
this.isSelectable = false;
|
||||
// Commented out to try to fix MacOS issue
|
||||
//this.sprite.resetPipeline();
|
||||
this.getOutlinePlugin()?.remove(this.sprite);
|
||||
}
|
||||
|
||||
private getOutlinePlugin(): OutlinePipelinePlugin|undefined {
|
||||
return this.sprite.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,30 +2,32 @@ import {EnableCameraSceneName} from "./EnableCameraScene";
|
|||
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||
import {loadAllLayers} from "../Entity/PlayerTexturesLoadingManager";
|
||||
import Sprite = Phaser.GameObjects.Sprite;
|
||||
import Container = Phaser.GameObjects.Container;
|
||||
import {gameManager} from "../Game/GameManager";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {addLoader} from "../Components/Loader";
|
||||
import type {BodyResourceDescriptionInterface} from "../Entity/PlayerTextures";
|
||||
import {AbstractCharacterScene} from "./AbstractCharacterScene";
|
||||
import {areCharacterLayersValid} from "../../Connexion/LocalUser";
|
||||
import { MenuScene } from "../Menu/MenuScene";
|
||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||
import {customCharacterSceneVisibleStore} from "../../Stores/CustomCharacterStore";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {isMobile} from "../../Enum/EnvironmentVariable";
|
||||
import {CustomizedCharacter} from "../Entity/CustomizedCharacter";
|
||||
|
||||
export const CustomizeSceneName = "CustomizeScene";
|
||||
|
||||
export const CustomizeSceneKey = "CustomizeScene";
|
||||
const customizeSceneKey = 'customizeScene';
|
||||
|
||||
export class CustomizeScene extends AbstractCharacterScene {
|
||||
private Rectangle!: Rectangle;
|
||||
|
||||
private selectedLayers: number[] = [0];
|
||||
private containersRow: Container[][] = [];
|
||||
private activeRow:number = 0;
|
||||
private containersRow: CustomizedCharacter[][] = [];
|
||||
public activeRow:number = 0;
|
||||
private layers: BodyResourceDescriptionInterface[][] = [];
|
||||
|
||||
private customizeSceneElement!: Phaser.GameObjects.DOMElement;
|
||||
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
||||
|
||||
private moveHorizontally: number = 0;
|
||||
private moveVertically: number = 0;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
|
@ -34,9 +36,7 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(customizeSceneKey, 'resources/html/CustomCharacterScene.html');
|
||||
|
||||
this.layers = loadAllLayers(this.load);
|
||||
this.loadCustomSceneSelectCharacters().then((bodyResourceDescriptions) => {
|
||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||
if(bodyResourceDescription.level == undefined || bodyResourceDescription.level < 0 || bodyResourceDescription.level > 5 ){
|
||||
|
@ -44,43 +44,28 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
}
|
||||
this.layers[bodyResourceDescription.level].unshift(bodyResourceDescription);
|
||||
});
|
||||
this.lazyloadingAttempt = true;
|
||||
});
|
||||
|
||||
this.layers = loadAllLayers(this.load);
|
||||
this.lazyloadingAttempt = false;
|
||||
|
||||
|
||||
//this function must stay at the end of preload function
|
||||
addLoader(this);
|
||||
}
|
||||
|
||||
create() {
|
||||
this.customizeSceneElement = this.add.dom(-1000, 0).createFromCache(customizeSceneKey);
|
||||
this.centerXDomElement(this.customizeSceneElement, 150);
|
||||
MenuScene.revealMenusAfterInit(this.customizeSceneElement, customizeSceneKey);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
customCharacterSceneVisibleStore.set(true);
|
||||
this.events.addListener('wake', () => {
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 3 : 1;
|
||||
customCharacterSceneVisibleStore.set(true);
|
||||
});
|
||||
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 3 : 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 / 3, 32, 33)
|
||||
this.Rectangle.setStrokeStyle(2, 0xFFFFFF);
|
||||
this.add.existing(this.Rectangle);
|
||||
|
@ -100,10 +85,13 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
this.backToPreviousScene();
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keyup-RIGHT', () => this.moveCursorHorizontally(1));
|
||||
this.input.keyboard.on('keyup-LEFT', () => this.moveCursorHorizontally(-1));
|
||||
this.input.keyboard.on('keyup-DOWN', () => this.moveCursorVertically(1));
|
||||
this.input.keyboard.on('keyup-UP', () => this.moveCursorVertically(-1));
|
||||
// Note: the key bindings are not directly put on the moveCursorVertically or moveCursorHorizontally methods
|
||||
// because if 2 such events are fired close to one another, it makes the whole application crawl to a halt (for a reason I cannot
|
||||
// explain, the list of sprites managed by the update list become immense
|
||||
this.input.keyboard.on('keyup-RIGHT', () => this.moveHorizontally = 1);
|
||||
this.input.keyboard.on('keyup-LEFT', () => this.moveHorizontally = -1);
|
||||
this.input.keyboard.on('keyup-DOWN', () => this.moveVertically = 1);
|
||||
this.input.keyboard.on('keyup-UP', () => this.moveVertically = -1);
|
||||
|
||||
const customCursorPosition = localUserStore.getCustomCursorPosition();
|
||||
if (customCursorPosition) {
|
||||
|
@ -116,7 +104,15 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
this.onResize();
|
||||
}
|
||||
|
||||
private moveCursorHorizontally(index: number): void {
|
||||
public moveCursorHorizontally(index: number): void {
|
||||
this.moveHorizontally = index;
|
||||
}
|
||||
|
||||
public moveCursorVertically(index: number): void {
|
||||
this.moveVertically = index;
|
||||
}
|
||||
|
||||
private doMoveCursorHorizontally(index: number): void {
|
||||
this.selectedLayers[this.activeRow] += index;
|
||||
if (this.selectedLayers[this.activeRow] < 0) {
|
||||
this.selectedLayers[this.activeRow] = 0
|
||||
|
@ -128,27 +124,7 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
this.saveInLocalStorage();
|
||||
}
|
||||
|
||||
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"/>`;
|
||||
}
|
||||
private doMoveCursorVertically(index:number): void {
|
||||
|
||||
this.activeRow += index;
|
||||
if (this.activeRow < 0) {
|
||||
|
@ -197,20 +173,20 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
* @param selectedItem, The number of the item select (0 for black body...)
|
||||
*/
|
||||
private generateCharacter(x: number, y: number, layerNumber: number, selectedItem: number) {
|
||||
return new Container(this, x, y,this.getContainerChildren(layerNumber,selectedItem));
|
||||
return new CustomizedCharacter(this, x, y, this.getContainerChildren(layerNumber,selectedItem));
|
||||
}
|
||||
|
||||
private getContainerChildren(layerNumber: number, selectedItem: number): Array<Sprite> {
|
||||
const children: Array<Sprite> = new Array<Sprite>();
|
||||
private getContainerChildren(layerNumber: number, selectedItem: number): Array<string> {
|
||||
const children: Array<string> = new Array<string>();
|
||||
for (let j = 0; j <= layerNumber; j++) {
|
||||
if (j === layerNumber) {
|
||||
children.push(this.generateLayers(0, 0, this.layers[j][selectedItem].name));
|
||||
children.push(this.layers[j][selectedItem].name);
|
||||
} else {
|
||||
const layer = this.selectedLayers[j];
|
||||
if (layer === undefined) {
|
||||
continue;
|
||||
}
|
||||
children.push(this.generateLayers(0, 0, this.layers[j][layer].name));
|
||||
children.push(this.layers[j][layer].name);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
|
@ -247,33 +223,47 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
* @return a new sprite
|
||||
*/
|
||||
private generateLayers(x: number, y: number, name: string): Sprite {
|
||||
return new Sprite(this, x, y, name);
|
||||
//return new Sprite(this, x, y, name);
|
||||
return this.add.sprite(0, 0, name);
|
||||
}
|
||||
|
||||
private updateSelectedLayer() {
|
||||
for(let i = 0; i < this.containersRow.length; i++){
|
||||
for(let j = 0; j < this.containersRow[i].length; j++){
|
||||
const children = this.getContainerChildren(i, j);
|
||||
this.containersRow[i][j].removeAll(true);
|
||||
this.containersRow[i][j].add(children);
|
||||
const children = this.getContainerChildren(i, j);
|
||||
this.containersRow[i][j].updateSprites(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
|
||||
if(this.lazyloadingAttempt){
|
||||
this.moveLayers();
|
||||
this.lazyloadingAttempt = false;
|
||||
}
|
||||
|
||||
if (this.moveHorizontally !== 0) {
|
||||
this.doMoveCursorHorizontally(this.moveHorizontally);
|
||||
this.moveHorizontally = 0;
|
||||
}
|
||||
if (this.moveVertically !== 0) {
|
||||
this.doMoveCursorVertically(this.moveVertically);
|
||||
this.moveVertically = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public onResize(): void {
|
||||
this.moveLayers();
|
||||
|
||||
this.Rectangle.x = this.cameras.main.worldView.x + this.cameras.main.width / 2;
|
||||
this.Rectangle.y = this.cameras.main.worldView.y + this.cameras.main.height / 3;
|
||||
|
||||
this.centerXDomElement(this.customizeSceneElement, 150);
|
||||
}
|
||||
|
||||
private nextSceneToCamera(){
|
||||
public nextSceneToCamera(){
|
||||
const layers: string[] = [];
|
||||
let i = 0;
|
||||
for (const layerItem of this.selectedLayers) {
|
||||
|
@ -288,12 +278,16 @@ export class CustomizeScene extends AbstractCharacterScene {
|
|||
|
||||
gameManager.setCharacterLayers(layers);
|
||||
this.scene.sleep(CustomizeSceneName);
|
||||
this.scene.remove(SelectCharacterSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
this.events.removeListener('wake');
|
||||
gameManager.tryResumingGame(this, EnableCameraSceneName);
|
||||
customCharacterSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
private backToPreviousScene(){
|
||||
public backToPreviousScene(){
|
||||
this.scene.sleep(CustomizeSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
this.scene.run(SelectCharacterSceneName);
|
||||
customCharacterSceneVisibleStore.set(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import {TextField} from "../Components/TextField";
|
|||
import Image = Phaser.GameObjects.Image;
|
||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
import {SoundMeter} from "../Components/SoundMeter";
|
||||
import {SoundMeterSprite} from "../Components/SoundMeterSprite";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {PinchManager} from "../UserInput/PinchManager";
|
||||
|
@ -11,304 +10,41 @@ import Zone = Phaser.GameObjects.Zone;
|
|||
import { MenuScene } from "../Menu/MenuScene";
|
||||
import {ResizableScene} from "./ResizableScene";
|
||||
import {
|
||||
audioConstraintStore,
|
||||
enableCameraSceneVisibilityStore,
|
||||
localStreamStore,
|
||||
mediaStreamConstraintsStore,
|
||||
videoConstraintStore
|
||||
} from "../../Stores/MediaStore";
|
||||
import type {Unsubscriber} from "svelte/store";
|
||||
|
||||
export const EnableCameraSceneName = "EnableCameraScene";
|
||||
enum LoginTextures {
|
||||
playButton = "play_button",
|
||||
icon = "icon",
|
||||
mainFont = "main_font",
|
||||
arrowRight = "arrow_right",
|
||||
arrowUp = "arrow_up"
|
||||
}
|
||||
|
||||
const enableCameraSceneKey = 'enableCameraScene';
|
||||
|
||||
export class EnableCameraScene extends ResizableScene {
|
||||
private textField!: TextField;
|
||||
private cameraNameField!: TextField;
|
||||
private arrowLeft!: Image;
|
||||
private arrowRight!: Image;
|
||||
private arrowDown!: Image;
|
||||
private arrowUp!: Image;
|
||||
private microphonesList: MediaDeviceInfo[] = new Array<MediaDeviceInfo>();
|
||||
private camerasList: MediaDeviceInfo[] = new Array<MediaDeviceInfo>();
|
||||
private cameraSelected: number = 0;
|
||||
private microphoneSelected: number = 0;
|
||||
private soundMeter: SoundMeter;
|
||||
private soundMeterSprite!: SoundMeterSprite;
|
||||
private microphoneNameField!: TextField;
|
||||
|
||||
private enableCameraSceneElement!: Phaser.GameObjects.DOMElement;
|
||||
|
||||
private mobileTapZone!: Zone;
|
||||
private localStreamStoreUnsubscriber!: Unsubscriber;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
key: EnableCameraSceneName
|
||||
});
|
||||
this.soundMeter = new SoundMeter();
|
||||
}
|
||||
|
||||
preload() {
|
||||
|
||||
this.load.html(enableCameraSceneKey, 'resources/html/EnableCameraScene.html');
|
||||
|
||||
this.load.image(LoginTextures.playButton, "resources/objects/play_button.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
|
||||
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
|
||||
}
|
||||
|
||||
create() {
|
||||
|
||||
this.enableCameraSceneElement = this.add.dom(-1000, 0).createFromCache(enableCameraSceneKey);
|
||||
this.centerXDomElement(this.enableCameraSceneElement, 300);
|
||||
|
||||
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);
|
||||
}
|
||||
//this.scale.setZoom(ZOOM_LEVEL);
|
||||
//Phaser.Display.Align.In.BottomCenter(this.pressReturnField, zone);
|
||||
|
||||
/* FIX ME */
|
||||
this.textField = new TextField(this, this.scale.width / 2, 20, '');
|
||||
|
||||
// For mobile purposes - we need a big enough touchable area.
|
||||
this.mobileTapZone = this.add.zone(this.scale.width / 2,this.scale.height - 30,200,50)
|
||||
.setInteractive().on("pointerdown", () => {
|
||||
this.login();
|
||||
});
|
||||
|
||||
this.cameraNameField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height - 60, '');
|
||||
|
||||
this.microphoneNameField = new TextField(this, this.game.renderer.width / 2, this.game.renderer.height - 40, '');
|
||||
|
||||
this.arrowRight = new Image(this, 0, 0, LoginTextures.arrowRight);
|
||||
this.arrowRight.setVisible(false);
|
||||
this.arrowRight.setInteractive().on('pointerdown', this.nextCam.bind(this));
|
||||
this.add.existing(this.arrowRight);
|
||||
|
||||
this.arrowLeft = new Image(this, 0, 0, LoginTextures.arrowRight);
|
||||
this.arrowLeft.setVisible(false);
|
||||
this.arrowLeft.flipX = true;
|
||||
this.arrowLeft.setInteractive().on('pointerdown', this.previousCam.bind(this));
|
||||
this.add.existing(this.arrowLeft);
|
||||
|
||||
this.arrowUp = new Image(this, 0, 0, LoginTextures.arrowUp);
|
||||
this.arrowUp.setVisible(false);
|
||||
this.arrowUp.setInteractive().on('pointerdown', this.previousMic.bind(this));
|
||||
this.add.existing(this.arrowUp);
|
||||
|
||||
this.arrowDown = new Image(this, 0, 0, LoginTextures.arrowUp);
|
||||
this.arrowDown.setVisible(false);
|
||||
this.arrowDown.flipY = true;
|
||||
this.arrowDown.setInteractive().on('pointerdown', this.nextMic.bind(this));
|
||||
this.add.existing(this.arrowDown);
|
||||
|
||||
this.input.keyboard.on('keyup-ENTER', () => {
|
||||
this.login();
|
||||
});
|
||||
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').classList.add('active');
|
||||
|
||||
this.localStreamStoreUnsubscriber = localStreamStore.subscribe((result) => {
|
||||
if (result.type === 'error') {
|
||||
// TODO: proper handling of the error
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
this.getDevices();
|
||||
if (result.stream !== null) {
|
||||
this.setupStream(result.stream);
|
||||
}
|
||||
});
|
||||
/*const mediaPromise = mediaManager.getCamera();
|
||||
mediaPromise.then(this.getDevices.bind(this));
|
||||
mediaPromise.then(this.setupStream.bind(this));*/
|
||||
|
||||
this.input.keyboard.on('keydown-RIGHT', this.nextCam.bind(this));
|
||||
this.input.keyboard.on('keydown-LEFT', this.previousCam.bind(this));
|
||||
this.input.keyboard.on('keydown-DOWN', this.nextMic.bind(this));
|
||||
this.input.keyboard.on('keydown-UP', this.previousMic.bind(this));
|
||||
|
||||
this.soundMeterSprite = new SoundMeterSprite(this, 50, 50);
|
||||
this.soundMeterSprite.setVisible(false);
|
||||
this.add.existing(this.soundMeterSprite);
|
||||
|
||||
this.onResize();
|
||||
|
||||
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
||||
}
|
||||
|
||||
private previousCam(): void {
|
||||
if (this.cameraSelected === 0 || this.camerasList.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.cameraSelected--;
|
||||
videoConstraintStore.setDeviceId(this.camerasList[this.cameraSelected].deviceId);
|
||||
|
||||
//mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
|
||||
}
|
||||
|
||||
private nextCam(): void {
|
||||
if (this.cameraSelected === this.camerasList.length - 1 || this.camerasList.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.cameraSelected++;
|
||||
videoConstraintStore.setDeviceId(this.camerasList[this.cameraSelected].deviceId);
|
||||
|
||||
// TODO: the change of camera should be OBSERVED (reactive)
|
||||
//mediaManager.setCamera(this.camerasList[this.cameraSelected].deviceId).then(this.setupStream.bind(this));
|
||||
}
|
||||
|
||||
private previousMic(): void {
|
||||
if (this.microphoneSelected === 0 || this.microphonesList.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.microphoneSelected--;
|
||||
audioConstraintStore.setDeviceId(this.microphonesList[this.microphoneSelected].deviceId);
|
||||
//mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
|
||||
}
|
||||
|
||||
private nextMic(): void {
|
||||
if (this.microphoneSelected === this.microphonesList.length - 1 || this.microphonesList.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.microphoneSelected++;
|
||||
audioConstraintStore.setDeviceId(this.microphonesList[this.microphoneSelected].deviceId);
|
||||
// TODO: the change of camera should be OBSERVED (reactive)
|
||||
//mediaManager.setMicrophone(this.microphonesList[this.microphoneSelected].deviceId).then(this.setupStream.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called each time a camera is changed
|
||||
*/
|
||||
private setupStream(stream: MediaStream): void {
|
||||
const img = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetupNoVideo');
|
||||
img.style.display = 'none';
|
||||
|
||||
const div = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('myCamVideoSetup');
|
||||
div.srcObject = stream;
|
||||
|
||||
this.soundMeter.connectToSource(stream, new window.AudioContext());
|
||||
this.soundMeterSprite.setVisible(true);
|
||||
|
||||
this.updateWebCamName();
|
||||
}
|
||||
|
||||
private updateWebCamName(): void {
|
||||
if (this.camerasList.length > 1) {
|
||||
let label = this.camerasList[this.cameraSelected].label;
|
||||
// remove text in parenthesis
|
||||
label = label.replace(/\([^()]*\)/g, '').trim();
|
||||
// remove accents
|
||||
label = label.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
this.cameraNameField.text = label;
|
||||
|
||||
this.arrowRight.setVisible(this.cameraSelected < this.camerasList.length - 1);
|
||||
this.arrowLeft.setVisible(this.cameraSelected > 0);
|
||||
}
|
||||
if (this.microphonesList.length > 1) {
|
||||
let label = this.microphonesList[this.microphoneSelected].label;
|
||||
// remove text in parenthesis
|
||||
label = label.replace(/\([^()]*\)/g, '').trim();
|
||||
// remove accents
|
||||
label = label.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
|
||||
this.microphoneNameField.text = label;
|
||||
|
||||
this.arrowDown.setVisible(this.microphoneSelected < this.microphonesList.length - 1);
|
||||
this.arrowUp.setVisible(this.microphoneSelected > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public onResize(): void {
|
||||
let div = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('myCamVideoSetup');
|
||||
let bounds = div.getBoundingClientRect();
|
||||
if (!div.srcObject) {
|
||||
div = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('webRtcSetup');
|
||||
bounds = div.getBoundingClientRect();
|
||||
}
|
||||
|
||||
this.textField.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.cameraNameField.y = bounds.top / this.scale.zoom - 8;
|
||||
|
||||
this.soundMeterSprite.x = this.game.renderer.width / 2 - this.soundMeterSprite.getWidth() / 2;
|
||||
this.soundMeterSprite.y = bounds.bottom / this.scale.zoom + 16;
|
||||
|
||||
this.microphoneNameField.y = this.soundMeterSprite.y + 22;
|
||||
|
||||
this.arrowRight.x = bounds.right / this.scale.zoom + 16;
|
||||
this.arrowRight.y = (bounds.top + bounds.height / 2) / this.scale.zoom;
|
||||
|
||||
this.arrowLeft.x = bounds.left / this.scale.zoom - 16;
|
||||
this.arrowLeft.y = (bounds.top + bounds.height / 2) / this.scale.zoom;
|
||||
|
||||
this.arrowDown.x = this.microphoneNameField.x + this.microphoneNameField.width / 2 + 16;
|
||||
this.arrowDown.y = this.microphoneNameField.y;
|
||||
|
||||
this.arrowUp.x = this.microphoneNameField.x - this.microphoneNameField.width / 2 - 16;
|
||||
this.arrowUp.y = this.microphoneNameField.y;
|
||||
|
||||
const actionBtn = document.querySelector<HTMLDivElement>('#enableCameraScene .action');
|
||||
if (actionBtn !== null) {
|
||||
actionBtn.style.top = (this.scale.height - 65) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
this.soundMeterSprite.setVolume(this.soundMeter.getVolume());
|
||||
|
||||
this.centerXDomElement(this.enableCameraSceneElement, 300);
|
||||
}
|
||||
|
||||
private login(): void {
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
|
||||
this.soundMeter.stop();
|
||||
|
||||
public login(): void {
|
||||
enableCameraSceneVisibilityStore.hideEnableCameraScene();
|
||||
this.localStreamStoreUnsubscriber();
|
||||
//mediaManager.stopCamera();
|
||||
//mediaManager.stopMicrophone();
|
||||
|
||||
this.scene.sleep(EnableCameraSceneName);
|
||||
gameManager.goToStartingMap(this.scene);
|
||||
}
|
||||
|
||||
private async getDevices() {
|
||||
// TODO: switch this in a store.
|
||||
const mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices();
|
||||
this.microphonesList = [];
|
||||
this.camerasList = [];
|
||||
for (const mediaDeviceInfo of mediaDeviceInfos) {
|
||||
if (mediaDeviceInfo.kind === 'audioinput') {
|
||||
this.microphonesList.push(mediaDeviceInfo);
|
||||
} else if (mediaDeviceInfo.kind === 'videoinput') {
|
||||
this.camerasList.push(mediaDeviceInfo);
|
||||
}
|
||||
}
|
||||
this.updateWebCamName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import {gameManager} from "../Game/GameManager";
|
||||
import {SelectCharacterSceneName} from "./SelectCharacterScene";
|
||||
import {ResizableScene} from "./ResizableScene";
|
||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import {MenuScene} from "../Menu/MenuScene";
|
||||
import { isUserNameValid } from "../../Connexion/LocalUser";
|
||||
import {loginSceneVisibleStore} from "../../Stores/LoginSceneStore";
|
||||
|
||||
export const LoginSceneName = "LoginScene";
|
||||
|
||||
const loginSceneKey = 'loginScene';
|
||||
|
||||
export class LoginScene extends ResizableScene {
|
||||
|
||||
private loginSceneElement!: Phaser.GameObjects.DOMElement;
|
||||
private name: string = '';
|
||||
|
||||
constructor() {
|
||||
|
@ -22,65 +17,25 @@ export class LoginScene extends ResizableScene {
|
|||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(loginSceneKey, 'resources/html/loginScene.html');
|
||||
}
|
||||
|
||||
create() {
|
||||
this.loginSceneElement = this.add.dom(-1000, 0).createFromCache(loginSceneKey);
|
||||
this.centerXDomElement(this.loginSceneElement, 200);
|
||||
MenuScene.revealMenusAfterInit(this.loginSceneElement, loginSceneKey);
|
||||
|
||||
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);
|
||||
});
|
||||
loginSceneVisibleStore.set(true);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if (this.name === '') return
|
||||
gameManager.setPlayerName(this.name);
|
||||
public login(name: string): void {
|
||||
name = name.trim();
|
||||
gameManager.setPlayerName(name);
|
||||
|
||||
this.scene.stop(LoginSceneName)
|
||||
gameManager.tryResumingGame(this, SelectCharacterSceneName);
|
||||
this.scene.remove(LoginSceneName)
|
||||
this.scene.remove(LoginSceneName);
|
||||
loginSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
this.centerXDomElement(this.loginSceneElement, 200);
|
||||
public onResize(): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Scene} from "phaser";
|
|||
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||
|
||||
export abstract class ResizableScene extends Scene {
|
||||
public abstract onResize(ev: UIEvent): void;
|
||||
public abstract onResize(): void;
|
||||
|
||||
/**
|
||||
* Centers the DOM element on the X axis.
|
||||
|
@ -17,7 +17,7 @@ export abstract class ResizableScene extends Scene {
|
|||
&& object.node
|
||||
&& object.node.getBoundingClientRect().width > 0
|
||||
? (object.node.getBoundingClientRect().width / 2 / this.scale.zoom)
|
||||
: (300 / this.scale.zoom)
|
||||
: (defaultWidth / this.scale.zoom)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,49 +4,50 @@ export class SelectCharacterMobileScene extends SelectCharacterScene {
|
|||
|
||||
create(){
|
||||
super.create();
|
||||
this.onResize();
|
||||
this.selectedRectangle.destroy();
|
||||
}
|
||||
|
||||
protected defineSetupPlayer(numero: number){
|
||||
protected defineSetupPlayer(num: number){
|
||||
const deltaX = 30;
|
||||
const deltaY = 2;
|
||||
let [playerX, playerY] = this.getCharacterPosition();
|
||||
let playerVisible = true;
|
||||
let playerScale = 1.5;
|
||||
let playserOpactity = 1;
|
||||
let playerOpacity = 1;
|
||||
|
||||
if( this.currentSelectUser !== numero ){
|
||||
if( this.currentSelectUser !== num ){
|
||||
playerVisible = false;
|
||||
}
|
||||
if( numero === (this.currentSelectUser + 1) ){
|
||||
if( num === (this.currentSelectUser + 1) ){
|
||||
playerY -= deltaY;
|
||||
playerX += deltaX;
|
||||
playerScale = 0.8;
|
||||
playserOpactity = 0.6;
|
||||
playerOpacity = 0.6;
|
||||
playerVisible = true;
|
||||
}
|
||||
if( numero === (this.currentSelectUser + 2) ){
|
||||
if( num === (this.currentSelectUser + 2) ){
|
||||
playerY -= deltaY;
|
||||
playerX += (deltaX * 2);
|
||||
playerScale = 0.8;
|
||||
playserOpactity = 0.6;
|
||||
playerOpacity = 0.6;
|
||||
playerVisible = true;
|
||||
}
|
||||
if( numero === (this.currentSelectUser - 1) ){
|
||||
if( num === (this.currentSelectUser - 1) ){
|
||||
playerY -= deltaY;
|
||||
playerX -= deltaX;
|
||||
playerScale = 0.8;
|
||||
playserOpactity = 0.6;
|
||||
playerOpacity = 0.6;
|
||||
playerVisible = true;
|
||||
}
|
||||
if( numero === (this.currentSelectUser - 2) ){
|
||||
if( num === (this.currentSelectUser - 2) ){
|
||||
playerY -= deltaY;
|
||||
playerX -= (deltaX * 2);
|
||||
playerScale = 0.8;
|
||||
playserOpactity = 0.6;
|
||||
playerOpacity = 0.6;
|
||||
playerVisible = true;
|
||||
}
|
||||
return {playerX, playerY, playerScale, playserOpactity, playerVisible}
|
||||
return {playerX, playerY, playerScale, playerOpacity, playerVisible}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,13 +10,13 @@ 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 {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {isMobile} from "../../Enum/EnvironmentVariable";
|
||||
|
||||
//todo: put this constants in a dedicated file
|
||||
export const SelectCharacterSceneName = "SelectCharacterScene";
|
||||
|
||||
const selectCharacterKey = 'selectCharacterScene';
|
||||
|
||||
export class SelectCharacterScene extends AbstractCharacterScene {
|
||||
protected readonly nbCharactersPerRow = 6;
|
||||
protected selectedPlayer!: Phaser.Physics.Arcade.Sprite|null; // null if we are selecting the "customize" option
|
||||
|
@ -25,8 +25,11 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
|
||||
protected selectedRectangle!: Rectangle;
|
||||
|
||||
protected selectCharacterSceneElement!: Phaser.GameObjects.DOMElement;
|
||||
protected currentSelectUser = 0;
|
||||
protected pointerClicked: boolean = false;
|
||||
protected pointerTimer: number = 0;
|
||||
|
||||
protected lazyloadingAttempt = true; //permit to update texture loaded after renderer
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
|
@ -35,50 +38,41 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(selectCharacterKey, 'resources/html/selectCharacterScene.html');
|
||||
|
||||
this.loadSelectSceneCharacters().then((bodyResourceDescriptions) => {
|
||||
bodyResourceDescriptions.forEach((bodyResourceDescription) => {
|
||||
this.playerModels.push(bodyResourceDescription);
|
||||
});
|
||||
})
|
||||
this.lazyloadingAttempt = true;
|
||||
});
|
||||
this.playerModels = loadAllDefaultModels(this.load);
|
||||
this.lazyloadingAttempt = false;
|
||||
|
||||
//this function must stay at the end of preload function
|
||||
addLoader(this);
|
||||
}
|
||||
|
||||
create() {
|
||||
|
||||
this.selectCharacterSceneElement = this.add.dom(-1000, 0).createFromCache(selectCharacterKey);
|
||||
this.centerXDomElement(this.selectCharacterSceneElement, 150);
|
||||
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();
|
||||
}
|
||||
selectCharacterSceneVisibleStore.set(true);
|
||||
this.events.addListener('wake', () => {
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
selectCharacterSceneVisibleStore.set(true);
|
||||
});
|
||||
|
||||
if (touchScreenManager.supportTouchScreen) {
|
||||
new PinchManager(this);
|
||||
}
|
||||
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
|
||||
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.selectedRectangle.setDepth(2);
|
||||
|
||||
/*create user*/
|
||||
this.createCurrentPlayer();
|
||||
const playerNumber = localUserStore.getPlayerCharacterIndex();
|
||||
|
||||
this.input.keyboard.on('keyup-ENTER', () => {
|
||||
return this.nextSceneToCameraScene();
|
||||
|
@ -98,7 +92,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
});
|
||||
}
|
||||
|
||||
protected nextSceneToCameraScene(): void {
|
||||
public nextSceneToCameraScene(): void {
|
||||
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
|
||||
return;
|
||||
}
|
||||
|
@ -106,23 +100,33 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
return;
|
||||
}
|
||||
this.scene.stop(SelectCharacterSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
gameManager.setCharacterLayers([this.selectedPlayer.texture.key]);
|
||||
gameManager.tryResumingGame(this, EnableCameraSceneName);
|
||||
this.scene.remove(SelectCharacterSceneName);
|
||||
this.players = [];
|
||||
selectCharacterSceneVisibleStore.set(false);
|
||||
this.events.removeListener('wake');
|
||||
}
|
||||
|
||||
protected nextSceneToCustomizeScene(): void {
|
||||
public nextSceneToCustomizeScene(): void {
|
||||
if (this.selectedPlayer !== null && !areCharacterLayersValid([this.selectedPlayer.texture.key])) {
|
||||
return;
|
||||
}
|
||||
this.scene.sleep(SelectCharacterSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
this.scene.run(CustomizeSceneName);
|
||||
selectCharacterSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
createCurrentPlayer(): void {
|
||||
for (let i = 0; i <this.playerModels.length; i++) {
|
||||
const playerResource = this.playerModels[i];
|
||||
|
||||
//check already exist texture
|
||||
if(this.players.find((c) => c.texture.key === playerResource.name)){
|
||||
continue;
|
||||
}
|
||||
|
||||
const [middleX, middleY] = this.getCharacterPosition();
|
||||
const player = this.physics.add.sprite(middleX, middleY, playerResource.name, 0);
|
||||
this.setUpPlayer(player, i);
|
||||
|
@ -133,15 +137,22 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
repeat: -1
|
||||
});
|
||||
player.setInteractive().on("pointerdown", () => {
|
||||
if(this.currentSelectUser === i){
|
||||
if (this.pointerClicked) {
|
||||
return;
|
||||
}
|
||||
if (this.currentSelectUser === i) {
|
||||
return;
|
||||
}
|
||||
//To not trigger two time the pointerdown events :
|
||||
// We set a boolean to true so that pointerdown events does nothing when the boolean is true
|
||||
// We set a timer that we decrease in update function to not trigger the pointerdown events twice
|
||||
this.pointerClicked = true;
|
||||
this.pointerTimer = 250;
|
||||
this.currentSelectUser = i;
|
||||
this.moveUser();
|
||||
});
|
||||
this.players.push(player);
|
||||
}
|
||||
|
||||
this.selectedPlayer = this.players[this.currentSelectUser];
|
||||
this.selectedPlayer.play(this.playerModels[this.currentSelectUser].name);
|
||||
}
|
||||
|
@ -154,7 +165,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
this.updateSelectedPlayer();
|
||||
}
|
||||
|
||||
protected moveToLeft(){
|
||||
public moveToLeft(){
|
||||
if(this.currentSelectUser === 0){
|
||||
return;
|
||||
}
|
||||
|
@ -162,7 +173,7 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
this.moveUser();
|
||||
}
|
||||
|
||||
protected moveToRight(){
|
||||
public moveToRight(){
|
||||
if(this.currentSelectUser === (this.players.length - 1)){
|
||||
return;
|
||||
}
|
||||
|
@ -186,35 +197,35 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
this.moveUser();
|
||||
}
|
||||
|
||||
protected defineSetupPlayer(numero: number){
|
||||
protected defineSetupPlayer(num: 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
|
||||
playerX = ( (playerX - (deltaX * 2.5)) + ((deltaX) * (num % this.nbCharactersPerRow)) ); // calcul position on line users
|
||||
playerY = ( (playerY - (deltaY * 2)) + ((deltaY) * ( Math.floor(num / this.nbCharactersPerRow) )) ); // calcul position on column users
|
||||
|
||||
const playerVisible = true;
|
||||
const playerScale = 1;
|
||||
const playserOpactity = 1;
|
||||
const playerOpacity = 1;
|
||||
|
||||
// if selected
|
||||
if( numero === this.currentSelectUser ){
|
||||
if( num === this.currentSelectUser ){
|
||||
this.selectedRectangle.setX(playerX);
|
||||
this.selectedRectangle.setY(playerY);
|
||||
}
|
||||
|
||||
return {playerX, playerY, playerScale, playserOpactity, playerVisible}
|
||||
return {playerX, playerY, playerScale, playerOpacity, playerVisible}
|
||||
}
|
||||
|
||||
protected setUpPlayer(player: Phaser.Physics.Arcade.Sprite, numero: number){
|
||||
protected setUpPlayer(player: Phaser.Physics.Arcade.Sprite, num: number){
|
||||
|
||||
const {playerX, playerY, playerScale, playserOpactity, playerVisible} = this.defineSetupPlayer(numero);
|
||||
const {playerX, playerY, playerScale, playerOpacity, playerVisible} = this.defineSetupPlayer(num);
|
||||
player.setBounce(0.2);
|
||||
player.setCollideWorldBounds(true);
|
||||
player.setCollideWorldBounds(false);
|
||||
player.setVisible( playerVisible );
|
||||
player.setScale(playerScale, playerScale);
|
||||
player.setAlpha(playserOpactity);
|
||||
player.setAlpha(playerOpacity);
|
||||
player.setX(playerX);
|
||||
player.setY(playerY);
|
||||
}
|
||||
|
@ -238,12 +249,23 @@ export class SelectCharacterScene extends AbstractCharacterScene {
|
|||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
// pointerTimer is set to 250 when pointerdown events is trigger
|
||||
// After 250ms, pointerClicked is set to false and the pointerdown events can be trigger again
|
||||
this.pointerTimer -= delta;
|
||||
if (this.pointerTimer <= 0) {
|
||||
this.pointerClicked = false;
|
||||
}
|
||||
|
||||
if(this.lazyloadingAttempt){
|
||||
//re-render players list
|
||||
this.createCurrentPlayer();
|
||||
this.moveUser();
|
||||
this.lazyloadingAttempt = false;
|
||||
}
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
public onResize(): void {
|
||||
//move position of user
|
||||
this.moveUser();
|
||||
|
||||
this.centerXDomElement(this.selectCharacterSceneElement, 150);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,18 +10,21 @@ import { getAllCompanionResources } from "../Companion/CompanionTexturesLoadingM
|
|||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {PinchManager} from "../UserInput/PinchManager";
|
||||
import { MenuScene } from "../Menu/MenuScene";
|
||||
import {selectCompanionSceneVisibleStore} from "../../Stores/SelectCompanionStore";
|
||||
import {waScaleManager} from "../Services/WaScaleManager";
|
||||
import {isMobile} from "../../Enum/EnvironmentVariable";
|
||||
|
||||
export const SelectCompanionSceneName = "SelectCompanionScene";
|
||||
|
||||
const selectCompanionSceneKey = 'selectCompanionScene';
|
||||
|
||||
export class SelectCompanionScene extends ResizableScene {
|
||||
private selectedCompanion!: Phaser.Physics.Arcade.Sprite;
|
||||
private companions: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
|
||||
private companionModels: Array<CompanionResourceDescriptionInterface> = [];
|
||||
private saveZoom: number = 0;
|
||||
|
||||
private selectCompanionSceneElement!: Phaser.GameObjects.DOMElement;
|
||||
private currentCompanion = 0;
|
||||
private pointerClicked: boolean = false;
|
||||
private pointerTimer: number = 0;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
|
@ -30,8 +33,6 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(selectCompanionSceneKey, 'resources/html/SelectCompanionScene.html');
|
||||
|
||||
getAllCompanionResources(this.load).forEach(model => {
|
||||
this.companionModels.push(model);
|
||||
});
|
||||
|
@ -42,30 +43,17 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
|
||||
create() {
|
||||
|
||||
this.selectCompanionSceneElement = this.add.dom(-1000, 0).createFromCache(selectCompanionSceneKey);
|
||||
this.centerXDomElement(this.selectCompanionSceneElement, 150);
|
||||
MenuScene.revealMenusAfterInit(this.selectCompanionSceneElement, selectCompanionSceneKey);
|
||||
selectCompanionSceneVisibleStore.set(true);
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
waScaleManager.saveZoom();
|
||||
waScaleManager.zoomModifier = isMobile() ? 2 : 1;
|
||||
|
||||
if (touchScreenManager.supportTouchScreen) {
|
||||
new PinchManager(this);
|
||||
}
|
||||
|
||||
// input events
|
||||
this.input.keyboard.on('keyup-ENTER', this.nextScene.bind(this));
|
||||
this.input.keyboard.on('keyup-ENTER', this.selectCompanion.bind(this));
|
||||
|
||||
this.input.keyboard.on('keydown-RIGHT', this.moveToRight.bind(this));
|
||||
this.input.keyboard.on('keydown-LEFT', this.moveToLeft.bind(this));
|
||||
|
@ -86,21 +74,28 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
|
||||
// pointerTimer is set to 250 when pointerdown events is trigger
|
||||
// After 250ms, pointerClicked is set to false and the pointerdown events can be trigger again
|
||||
this.pointerTimer -= delta;
|
||||
if (this.pointerTimer <= 0) {
|
||||
this.pointerClicked = false;
|
||||
}
|
||||
}
|
||||
|
||||
private nextScene(): void {
|
||||
public selectCompanion(): void {
|
||||
localUserStore.setCompanion(this.companionModels[this.currentCompanion].name);
|
||||
gameManager.setCompanion(this.companionModels[this.currentCompanion].name);
|
||||
|
||||
this._nextScene();
|
||||
this.closeScene();
|
||||
}
|
||||
|
||||
private _nextScene(){
|
||||
public closeScene(){
|
||||
// next scene
|
||||
this.scene.stop(SelectCompanionSceneName);
|
||||
waScaleManager.restoreZoom();
|
||||
gameManager.tryResumingGame(this, EnableCameraSceneName);
|
||||
this.scene.remove(SelectCompanionSceneName);
|
||||
selectCompanionSceneVisibleStore.set(false);
|
||||
}
|
||||
|
||||
private createCurrentCompanion(): void {
|
||||
|
@ -117,6 +112,14 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
});
|
||||
|
||||
companion.setInteractive().on("pointerdown", () => {
|
||||
if (this.pointerClicked) {
|
||||
return;
|
||||
}
|
||||
//To not trigger two time the pointerdown events :
|
||||
// We set a boolean to true so that pointerdown events does nothing when the boolean is true
|
||||
// We set a timer that we decrease in update function to not trigger the pointerdown events twice
|
||||
this.pointerClicked = true;
|
||||
this.pointerTimer = 250;
|
||||
this.currentCompanion = i;
|
||||
this.moveCompanion();
|
||||
});
|
||||
|
@ -126,10 +129,8 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
this.selectedCompanion = this.companions[this.currentCompanion];
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
public onResize(): void {
|
||||
this.moveCompanion();
|
||||
|
||||
this.centerXDomElement(this.selectCompanionSceneElement, 150);
|
||||
}
|
||||
|
||||
private updateSelectedCompanion(): void {
|
||||
|
@ -147,15 +148,7 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
this.updateSelectedCompanion();
|
||||
}
|
||||
|
||||
private moveToLeft(){
|
||||
if(this.currentCompanion === 0){
|
||||
return;
|
||||
}
|
||||
this.currentCompanion -= 1;
|
||||
this.moveCompanion();
|
||||
}
|
||||
|
||||
private moveToRight(){
|
||||
public moveToRight(){
|
||||
if(this.currentCompanion === (this.companions.length - 1)){
|
||||
return;
|
||||
}
|
||||
|
@ -163,38 +156,46 @@ export class SelectCompanionScene extends ResizableScene {
|
|||
this.moveCompanion();
|
||||
}
|
||||
|
||||
private defineSetupCompanion(numero: number){
|
||||
public moveToLeft(){
|
||||
if(this.currentCompanion === 0){
|
||||
return;
|
||||
}
|
||||
this.currentCompanion -= 1;
|
||||
this.moveCompanion();
|
||||
}
|
||||
|
||||
private defineSetupCompanion(num: 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 ){
|
||||
if( this.currentCompanion !== num ){
|
||||
companionVisible = false;
|
||||
}
|
||||
if( numero === (this.currentCompanion + 1) ){
|
||||
if( num === (this.currentCompanion + 1) ){
|
||||
companionY -= deltaY;
|
||||
companionX += deltaX;
|
||||
companionScale = 0.8;
|
||||
companionOpactity = 0.6;
|
||||
companionVisible = true;
|
||||
}
|
||||
if( numero === (this.currentCompanion + 2) ){
|
||||
if( num === (this.currentCompanion + 2) ){
|
||||
companionY -= deltaY;
|
||||
companionX += (deltaX * 2);
|
||||
companionScale = 0.8;
|
||||
companionOpactity = 0.6;
|
||||
companionVisible = true;
|
||||
}
|
||||
if( numero === (this.currentCompanion - 1) ){
|
||||
if( num === (this.currentCompanion - 1) ){
|
||||
companionY -= deltaY;
|
||||
companionX -= deltaX;
|
||||
companionScale = 0.8;
|
||||
companionOpactity = 0.6;
|
||||
companionVisible = true;
|
||||
}
|
||||
if( numero === (this.currentCompanion - 2) ){
|
||||
if( num === (this.currentCompanion - 2) ){
|
||||
companionY -= deltaY;
|
||||
companionX -= (deltaX * 2);
|
||||
companionScale = 0.8;
|
||||
|
|
|
@ -170,7 +170,7 @@ export interface ITiledTileSet {
|
|||
tilewidth: number;
|
||||
transparentcolor: string;
|
||||
terrains: ITiledMapTerrain[];
|
||||
tiles: Array<ITile>;
|
||||
tiles?: Array<ITile>;
|
||||
|
||||
/**
|
||||
* Refers to external tileset file (should be JSON)
|
||||
|
@ -181,6 +181,8 @@ export interface ITiledTileSet {
|
|||
export interface ITile {
|
||||
id: number,
|
||||
type?: string
|
||||
|
||||
properties?: Array<ITiledMapLayerProperty>
|
||||
}
|
||||
|
||||
export interface ITiledMapTerrain {
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {DirtyScene} from "../Game/DirtyScene";
|
||||
import {get} from "svelte/store";
|
||||
import {requestedCameraState, requestedMicrophoneState} from "../../Stores/MediaStore";
|
||||
|
||||
export const HelpCameraSettingsSceneName = 'HelpCameraSettingsScene';
|
||||
const helpCameraSettings = 'helpCameraSettings';
|
||||
/**
|
||||
* The scene that show how to permit Camera and Microphone access if there are not already allowed
|
||||
*/
|
||||
export class HelpCameraSettingsScene extends DirtyScene {
|
||||
private helpCameraSettingsElement!: Phaser.GameObjects.DOMElement;
|
||||
private helpCameraSettingsOpened: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super({key: HelpCameraSettingsSceneName});
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.html(helpCameraSettings, 'resources/html/helpCameraSettings.html');
|
||||
}
|
||||
|
||||
create(){
|
||||
this.createHelpCameraSettings();
|
||||
}
|
||||
|
||||
private createHelpCameraSettings() : void {
|
||||
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();
|
||||
}else if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormContinue') {
|
||||
this.closeHelpCameraSettingsOpened();
|
||||
}
|
||||
});
|
||||
|
||||
if(!localUserStore.getHelpCameraSettingsShown() && (!get(requestedMicrophoneState) || !get(requestedCameraState))){
|
||||
this.openHelpCameraSettingsOpened();
|
||||
localUserStore.setHelpCameraSettingsShown();
|
||||
}
|
||||
|
||||
mediaManager.setHelpCameraSettingsCallBack(() => {
|
||||
this.openHelpCameraSettingsOpened();
|
||||
});
|
||||
}
|
||||
|
||||
private openHelpCameraSettingsOpened(): void{
|
||||
HtmlUtils.getElementByIdOrFail<HTMLDivElement>('webRtcSetup').style.display = 'none';
|
||||
this.helpCameraSettingsOpened = true;
|
||||
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,
|
||||
x: middleX,
|
||||
duration: 1000,
|
||||
ease: 'Power3',
|
||||
overflow: 'scroll'
|
||||
});
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private closeHelpCameraSettingsOpened(): void{
|
||||
const middleX = this.getMiddleX();
|
||||
/*const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement;
|
||||
helpCameraSettingsInfo.innerText = '';
|
||||
helpCameraSettingsInfo.style.display = 'none';*/
|
||||
this.helpCameraSettingsOpened = false;
|
||||
this.tweens.add({
|
||||
targets: this.helpCameraSettingsElement,
|
||||
y: -1000,
|
||||
x: middleX,
|
||||
duration: 1000,
|
||||
ease: 'Power3',
|
||||
overflow: 'scroll'
|
||||
});
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private revealMenusAfterInit(menuElement: Phaser.GameObjects.DOMElement, rootDomId: string) {
|
||||
//Dom elements will appear inside the viewer screen when creating before being moved out of it, which create a flicker effect.
|
||||
//To prevent this, we put a 'hidden' attribute on the root element, we remove it only after the init is done.
|
||||
setTimeout(() => {
|
||||
(menuElement.getChildByID(rootDomId) as HTMLElement).hidden = false;
|
||||
}, 250);
|
||||
}
|
||||
|
||||
update(time: number, delta: number): void {
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
public onResize(ev: UIEvent): void {
|
||||
super.onResize(ev);
|
||||
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'
|
||||
});
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private getMiddleX() : number{
|
||||
return (this.scale.width / 2) -
|
||||
(
|
||||
this.helpCameraSettingsElement
|
||||
&& this.helpCameraSettingsElement.node
|
||||
&& this.helpCameraSettingsElement.node.getBoundingClientRect().width > 0
|
||||
? (this.helpCameraSettingsElement.node.getBoundingClientRect().width / (2 * this.scale.zoom))
|
||||
: (400 / 2)
|
||||
);
|
||||
}
|
||||
|
||||
private getMiddleY() : number{
|
||||
const middleY = ((this.scale.height) - (
|
||||
(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*/)/this.scale.zoom)) / 2;
|
||||
return (middleY > 0 ? middleY : 0);
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return this.dirty;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,10 @@ import { HtmlUtils } from '../../WebRtc/HtmlUtils';
|
|||
import { iframeListener } from '../../Api/IframeListener';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { videoConstraintStore } from "../../Stores/MediaStore";
|
||||
import {registerMenuCommandStream} from "../../Api/Events/ui/MenuItemRegisterEvent";
|
||||
import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem";
|
||||
import {consoleGlobalMessageManagerVisibleStore} from "../../Stores/ConsoleGlobalMessageManagerStore";
|
||||
import {get} from "svelte/store";
|
||||
|
||||
export const MenuSceneName = 'MenuScene';
|
||||
const gameMenuKey = 'gameMenu';
|
||||
|
@ -42,18 +46,39 @@ export class MenuScene extends Phaser.Scene {
|
|||
private warningContainerTimeout: NodeJS.Timeout | null = null;
|
||||
private subscriptions = new Subscription()
|
||||
constructor() {
|
||||
super({key: MenuSceneName});
|
||||
super({ key: MenuSceneName });
|
||||
|
||||
this.gameQualityValue = localUserStore.getGameQualityValue();
|
||||
this.videoQualityValue = localUserStore.getVideoQualityValue();
|
||||
|
||||
this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => {
|
||||
this.subscriptions.add(registerMenuCommandStream.subscribe(menuCommand => {
|
||||
this.addMenuOption(menuCommand);
|
||||
}))
|
||||
|
||||
this.subscriptions.add(iframeListener.unregisterMenuCommandStream.subscribe(menuCommand => {
|
||||
this.destroyMenu(menuCommand);
|
||||
}))
|
||||
}
|
||||
|
||||
preload () {
|
||||
reset() {
|
||||
const addedMenuItems = [...this.menuElement.node.querySelectorAll(".fromApi")];
|
||||
for (let index = addedMenuItems.length - 1; index >= 0; index--) {
|
||||
addedMenuItems[index].remove()
|
||||
}
|
||||
}
|
||||
|
||||
public addMenuOption(menuText: string) {
|
||||
const wrappingSection = document.createElement("section")
|
||||
const escapedHtml = HtmlUtils.escapeHtml(menuText);
|
||||
wrappingSection.innerHTML = `<button class="fromApi" id="${escapedHtml}">${escapedHtml}</button>`
|
||||
const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main");
|
||||
if (menuItemContainer) {
|
||||
menuItemContainer.querySelector(`#${escapedHtml}.fromApi`)?.remove()
|
||||
menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks"))
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
|
@ -62,13 +87,6 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.load.html(warningContainerKey, warningContainerHtml);
|
||||
}
|
||||
|
||||
reset() {
|
||||
const addedMenuItems=[...this.menuElement.node.querySelectorAll(".fromApi")];
|
||||
for(let index=addedMenuItems.length-1;index>=0;index--){
|
||||
addedMenuItems[index].remove()
|
||||
}
|
||||
}
|
||||
|
||||
create() {
|
||||
menuIconVisible.set(true);
|
||||
this.menuElement = this.add.dom(closedSideMenuX, 30).createFromCache(gameMenuKey);
|
||||
|
@ -83,11 +101,11 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.gameShareElement = this.add.dom(middleX, -400).createFromCache(gameShare);
|
||||
MenuScene.revealMenusAfterInit(this.gameShareElement, gameShare);
|
||||
this.gameShareElement.addListener('click');
|
||||
this.gameShareElement.on('click', (event:MouseEvent) => {
|
||||
this.gameShareElement.on('click', (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
if((event?.target as HTMLInputElement).id === 'gameShareFormSubmit') {
|
||||
if ((event?.target as HTMLInputElement).id === 'gameShareFormSubmit') {
|
||||
this.copyLink();
|
||||
}else if((event?.target as HTMLInputElement).id === 'gameShareFormCancel') {
|
||||
} else if ((event?.target as HTMLInputElement).id === 'gameShareFormCancel') {
|
||||
this.closeGameShare();
|
||||
}
|
||||
});
|
||||
|
@ -143,8 +161,8 @@ export class MenuScene extends Phaser.Scene {
|
|||
}
|
||||
//TODO bind with future metadata of card
|
||||
//if (connectionManager.getConnexionType === GameConnexionTypes.anonymous){
|
||||
const adminSection = this.menuElement.getChildByID('socialLinks') as HTMLElement;
|
||||
adminSection.hidden = false;
|
||||
const adminSection = this.menuElement.getChildByID('socialLinks') as HTMLElement;
|
||||
adminSection.hidden = false;
|
||||
//}
|
||||
this.tweens.add({
|
||||
targets: this.menuElement,
|
||||
|
@ -174,7 +192,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.sideMenuOpened = false;
|
||||
this.closeAll();
|
||||
this.menuButton.getChildByID('openMenuButton').innerHTML = `<img src="/static/images/menu.svg">`;
|
||||
gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.disabledMessageConsole();
|
||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||
this.tweens.add({
|
||||
targets: this.menuElement,
|
||||
x: closedSideMenuX,
|
||||
|
@ -194,28 +212,28 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.settingsMenuOpened = true;
|
||||
|
||||
const gameQualitySelect = this.gameQualityMenuElement.getChildByID('select-game-quality') as HTMLInputElement;
|
||||
gameQualitySelect.value = ''+this.gameQualityValue;
|
||||
gameQualitySelect.value = '' + this.gameQualityValue;
|
||||
const videoQualitySelect = this.gameQualityMenuElement.getChildByID('select-video-quality') as HTMLInputElement;
|
||||
videoQualitySelect.value = ''+this.videoQualityValue;
|
||||
videoQualitySelect.value = '' + this.videoQualityValue;
|
||||
|
||||
this.gameQualityMenuElement.addListener('click');
|
||||
this.gameQualityMenuElement.on('click', (event:MouseEvent) => {
|
||||
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') {
|
||||
} else if ((event?.target as HTMLInputElement).id === 'gameQualityFormCancel') {
|
||||
this.closeGameQualityMenu();
|
||||
}
|
||||
});
|
||||
|
||||
let middleY = this.scale.height / 2 - 392/2;
|
||||
if(middleY < 0){
|
||||
let middleY = this.scale.height / 2 - 392 / 2;
|
||||
if (middleY < 0) {
|
||||
middleY = 0;
|
||||
}
|
||||
let middleX = this.scale.width / 2 - 457/2;
|
||||
if(middleX < 0){
|
||||
let middleX = this.scale.width / 2 - 457 / 2;
|
||||
if (middleX < 0) {
|
||||
middleX = 0;
|
||||
}
|
||||
this.tweens.add({
|
||||
|
@ -241,7 +259,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
}
|
||||
|
||||
|
||||
private openGameShare(): void{
|
||||
private openGameShare(): void {
|
||||
if (this.gameShareOpened) {
|
||||
this.closeGameShare();
|
||||
return;
|
||||
|
@ -255,11 +273,11 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.gameShareOpened = true;
|
||||
|
||||
let middleY = this.scale.height / 2 - 85;
|
||||
if(middleY < 0){
|
||||
if (middleY < 0) {
|
||||
middleY = 0;
|
||||
}
|
||||
let middleX = this.scale.width / 2 - 200;
|
||||
if(middleX < 0){
|
||||
if (middleX < 0) {
|
||||
middleX = 0;
|
||||
}
|
||||
this.tweens.add({
|
||||
|
@ -271,7 +289,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
});
|
||||
}
|
||||
|
||||
private closeGameShare(): void{
|
||||
private closeGameShare(): void {
|
||||
const gameShareInfo = this.gameShareElement.getChildByID('gameShareInfo') as HTMLParagraphElement;
|
||||
gameShareInfo.innerText = '';
|
||||
gameShareInfo.style.display = 'none';
|
||||
|
@ -284,17 +302,6 @@ export class MenuScene extends Phaser.Scene {
|
|||
});
|
||||
}
|
||||
|
||||
public addMenuOption(menuText: string) {
|
||||
const wrappingSection = document.createElement("section")
|
||||
const excapedHtml = HtmlUtils.escapeHtml(menuText);
|
||||
wrappingSection.innerHTML = `<button class="fromApi" id="${excapedHtml}">${excapedHtml}</button>`
|
||||
const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main");
|
||||
if (menuItemContainer) {
|
||||
menuItemContainer.querySelector(`#${excapedHtml}.fromApi`)?.remove()
|
||||
menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks"))
|
||||
}
|
||||
}
|
||||
|
||||
private onMenuClick(event: MouseEvent) {
|
||||
const htmlMenuItem = (event?.target as HTMLInputElement);
|
||||
if (htmlMenuItem.classList.contains('not-button')) {
|
||||
|
@ -303,11 +310,11 @@ export class MenuScene extends Phaser.Scene {
|
|||
event.preventDefault();
|
||||
|
||||
if (htmlMenuItem.classList.contains("fromApi")) {
|
||||
iframeListener.sendMenuClickedEvent(htmlMenuItem.id)
|
||||
sendMenuClickedEvent(htmlMenuItem.id)
|
||||
return
|
||||
}
|
||||
|
||||
switch (htmlMenuItem.id) {
|
||||
switch ((event?.target as HTMLInputElement).id) {
|
||||
case 'changeNameButton':
|
||||
this.closeSideMenu();
|
||||
gameManager.leaveGame(this, LoginSceneName, new LoginScene());
|
||||
|
@ -336,7 +343,11 @@ export class MenuScene extends Phaser.Scene {
|
|||
this.toggleFullscreen();
|
||||
break;
|
||||
case 'adminConsoleButton':
|
||||
gameManager.getCurrentGameScene(this).ConsoleGlobalMessageManager.activeMessageConsole();
|
||||
if (get(consoleGlobalMessageManagerVisibleStore)) {
|
||||
consoleGlobalMessageManagerVisibleStore.set(false);
|
||||
} else {
|
||||
consoleGlobalMessageManagerVisibleStore.set(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +359,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
gameShareInfo.style.display = 'block';
|
||||
}
|
||||
|
||||
private saveSetting(valueGame: number, valueVideo: number){
|
||||
private saveSetting(valueGame: number, valueVideo: number) {
|
||||
if (valueGame !== this.gameQualityValue) {
|
||||
this.gameQualityValue = valueGame;
|
||||
localUserStore.setGameQualityValue(valueGame);
|
||||
|
@ -369,7 +380,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
window.open(sparkHost, '_blank');
|
||||
}
|
||||
|
||||
private closeAll(){
|
||||
private closeAll() {
|
||||
this.closeGameQualityMenu();
|
||||
this.closeGameShare();
|
||||
this.gameReportElement.close();
|
||||
|
@ -386,6 +397,10 @@ export class MenuScene extends Phaser.Scene {
|
|||
}
|
||||
}
|
||||
|
||||
public destroyMenu(menu: string) {
|
||||
this.menuElement.getChildByID(menu).remove();
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export class Player extends Character {
|
|||
companion: string|null,
|
||||
companionTexturePromise?: Promise<string>
|
||||
) {
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, companion, companionTexturePromise);
|
||||
super(Scene, x, y, texturesPromise, name, direction, moving, 1, true, companion, companionTexturePromise);
|
||||
|
||||
//the current player model should be push away by other players to prevent conflict
|
||||
this.getBody().setImmovable(false);
|
||||
|
@ -102,10 +102,6 @@ export class Player extends Character {
|
|||
}
|
||||
}
|
||||
|
||||
isClickable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
openEmoteMenu(emotes:RadialMenuItem[]): void {
|
||||
this.cancelPreviousEmote();
|
||||
this.emoteMenu = new RadialMenu(this.scene, this.x, this.y, emotes)
|
||||
|
|
|
@ -2,6 +2,8 @@ import {HdpiManager} from "./HdpiManager";
|
|||
import ScaleManager = Phaser.Scale.ScaleManager;
|
||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||
import type {Game} from "../Game/Game";
|
||||
import {ResizableScene} from "../Login/ResizableScene";
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
|
||||
|
||||
class WaScaleManager {
|
||||
|
@ -9,6 +11,7 @@ class WaScaleManager {
|
|||
private scaleManager!: ScaleManager;
|
||||
private game!: Game;
|
||||
private actualZoom: number = 1;
|
||||
private _saveZoom: number = 1;
|
||||
|
||||
public constructor(private minGamePixelsNumber: number, private absoluteMinPixelNumber: number) {
|
||||
this.hdpiManager = new HdpiManager(minGamePixelsNumber, absoluteMinPixelNumber);
|
||||
|
@ -30,7 +33,7 @@ class WaScaleManager {
|
|||
const { game: gameSize, real: realSize } = this.hdpiManager.getOptimalGameSize({width: width * devicePixelRatio, height: height * devicePixelRatio});
|
||||
|
||||
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
|
||||
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);
|
||||
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio)
|
||||
this.scaleManager.resize(gameSize.width, gameSize.height);
|
||||
|
||||
// Override bug in canvas resizing in Phaser. Let's resize the canvas ourselves
|
||||
|
@ -38,6 +41,19 @@ class WaScaleManager {
|
|||
style.width = Math.ceil(realSize.width / devicePixelRatio) + 'px';
|
||||
style.height = Math.ceil(realSize.height / devicePixelRatio) + 'px';
|
||||
|
||||
// Resize the game element at the same size at the canvas
|
||||
const gameStyle = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('game').style;
|
||||
gameStyle.width = style.width;
|
||||
gameStyle.height = style.height;
|
||||
|
||||
// Note: onResize will be called twice (once here and once in Game.ts), but we have no better way.
|
||||
for (const scene of this.game.scene.getScenes(true)) {
|
||||
if (scene instanceof ResizableScene) {
|
||||
// We are delaying the call to the "render" event because otherwise, the "camera" coordinates are not correctly updated.
|
||||
scene.events.once(Phaser.Scenes.Events.RENDER, () => scene.onResize());
|
||||
}
|
||||
}
|
||||
|
||||
this.game.markDirty();
|
||||
}
|
||||
|
||||
|
@ -50,6 +66,15 @@ class WaScaleManager {
|
|||
this.applyNewSize();
|
||||
}
|
||||
|
||||
public saveZoom(): void {
|
||||
this._saveZoom = this.hdpiManager.zoomModifier;
|
||||
}
|
||||
|
||||
public restoreZoom(): void{
|
||||
this.hdpiManager.zoomModifier = this._saveZoom;
|
||||
this.applyNewSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to scale back the ui components to counter-act the zoom.
|
||||
*/
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
export class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline {
|
||||
|
||||
// the unique id of this pipeline
|
||||
public static readonly KEY = 'Outline';
|
||||
|
||||
/**
|
||||
* @param {Phaser.Game} game - the controller of the game instance
|
||||
*/
|
||||
constructor(game: Phaser.Game)
|
||||
{
|
||||
super({
|
||||
game: game,
|
||||
fragShader: `
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D uMainSampler;
|
||||
uniform vec2 uTextureSize;
|
||||
|
||||
varying vec2 outTexCoord;
|
||||
varying float outTintEffect;
|
||||
varying vec4 outTint;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 texture = texture2D(uMainSampler, outTexCoord);
|
||||
vec4 texel = vec4(outTint.rgb * outTint.a, outTint.a);
|
||||
vec4 color = texture;
|
||||
|
||||
if (outTintEffect == 0.0)
|
||||
{
|
||||
color = texture * texel;
|
||||
}
|
||||
else if (outTintEffect == 1.0)
|
||||
{
|
||||
color.rgb = mix(texture.rgb, outTint.rgb * outTint.a, texture.a);
|
||||
color.a = texture.a * texel.a;
|
||||
}
|
||||
else if (outTintEffect == 2.0)
|
||||
{
|
||||
color = texel;
|
||||
}
|
||||
|
||||
vec2 onePixel = vec2(1.0, 1.0) / uTextureSize;
|
||||
float upAlpha = texture2D(uMainSampler, outTexCoord + vec2(0.0, onePixel.y)).a;
|
||||
float leftAlpha = texture2D(uMainSampler, outTexCoord + vec2(-onePixel.x, 0.0)).a;
|
||||
float downAlpha = texture2D(uMainSampler, outTexCoord + vec2(0.0, -onePixel.y)).a;
|
||||
float rightAlpha = texture2D(uMainSampler, outTexCoord + vec2(onePixel.x, 0.0)).a;
|
||||
|
||||
if (texture.a == 0.0 && max(max(upAlpha, downAlpha), max(leftAlpha, rightAlpha)) == 1.0)
|
||||
{
|
||||
color = vec4(1.0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
`
|
||||
});
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import type { Direction } from "../../types";
|
|||
import type {GameScene} from "../Game/GameScene";
|
||||
import {touchScreenManager} from "../../Touch/TouchScreenManager";
|
||||
import {MobileJoystick} from "../Components/MobileJoystick";
|
||||
import {enableUserInputsStore} from "../../Stores/UserInputStore";
|
||||
|
||||
interface UserInputManagerDatum {
|
||||
keyInstance: Phaser.Input.Keyboard.Key;
|
||||
|
@ -58,6 +59,10 @@ export class UserInputManager {
|
|||
if (touchScreenManager.supportTouchScreen) {
|
||||
this.initVirtualJoystick();
|
||||
}
|
||||
|
||||
enableUserInputsStore.subscribe((enable) => {
|
||||
enable ? this.restoreControls() : this.disableControls()
|
||||
})
|
||||
}
|
||||
|
||||
initVirtualJoystick() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue