From 80a5d2e30e29b340f25bd364caa24e7c3278e5e8 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Thu, 1 Apr 2021 00:33:05 +0200 Subject: [PATCH 01/20] added random companion to player --- front/src/Phaser/Companion/Companion.ts | 196 ++++++++++++++++++ .../src/Phaser/Companion/CompanionTextures.ts | 14 ++ .../CompanionTexturesLoadingManager.ts | 30 +++ front/src/Phaser/Player/Player.ts | 17 +- 4 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 front/src/Phaser/Companion/Companion.ts create mode 100644 front/src/Phaser/Companion/CompanionTextures.ts create mode 100644 front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts new file mode 100644 index 00000000..ab9b8be8 --- /dev/null +++ b/front/src/Phaser/Companion/Companion.ts @@ -0,0 +1,196 @@ +import Sprite = Phaser.GameObjects.Sprite; +import Container = Phaser.GameObjects.Container; +import { lazyLoadResource } from "./CompanionTexturesLoadingManager"; +import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation"; + +export class Companion extends Container { + public sprites: Map; + + private delta: number; + private invisible: boolean; + private target: { x: number, y: number }; + + constructor( + scene: Phaser.Scene, + x: number, + y: number + ) { + super(scene, x, y); + + this.delta = 0; + this.invisible = true; + this.target = { x, y }; + this.sprites = new Map(); + + const animal = ["dog1", "dog2", "dog3", "cat1", "cat2", "cat3"]; + const random = Math.floor(Math.random() * animal.length); + + lazyLoadResource(this.scene.load, animal[random]).then(resource => { + this.addResource(resource); + this.invisible = false; + }) + + this.scene.physics.world.enableBody(this); + + this.getBody().setImmovable(true); + this.getBody().setCollideWorldBounds(true); + this.setSize(16, 16); + this.getBody().setSize(16, 16); + this.getBody().setOffset(0, 8); + + this.setDepth(-1); + + scene.game.events.addListener('step', this.step.bind(this)); + scene.add.existing(this); + } + + public setTarget(x: number, y: number) { + this.target = { x, y }; + } + + private step(time: any, delta: any) { + if (typeof this.target === 'undefined') return; + + this.delta += delta; + if (this.delta < 256) { + return; + } + this.delta = 0; + + const xDist = this.target.x - this.x; + const yDist = this.target.y - this.y; + + let direction: PlayerAnimationDirections; + let type: PlayerAnimationTypes; + + const distance = Math.sqrt(Math.pow(Math.abs(xDist), 2) + Math.pow(Math.abs(yDist), 2)); + + if (distance < 16) { + type = PlayerAnimationTypes.Idle; + this.getBody().stop(); + } else { + type = PlayerAnimationTypes.Walk; + + const xDir = xDist / Math.max(Math.abs(xDist), 1); + const yDir = yDist / Math.max(Math.abs(yDist), 1); + + const speed = 256; + this.getBody().setVelocity(Math.min(Math.abs(xDist * 2), speed) * xDir, Math.min(Math.abs(yDist * 2), speed) * yDir); + } + + if (Math.abs(xDist) > Math.abs(yDist)) { + if (xDist < 0) { + direction = PlayerAnimationDirections.Left; + } else { + direction = PlayerAnimationDirections.Right; + } + } else { + if (yDist < 0) { + direction = PlayerAnimationDirections.Up; + } else { + direction = PlayerAnimationDirections.Down; + } + } + + this.setDepth(this.y); + this.playAnimation(direction, type); + } + + private playAnimation(direction: PlayerAnimationDirections, type: PlayerAnimationTypes): void { + if (this.invisible) return; + + for (const [resource, sprite] of this.sprites.entries()) { + sprite.play(`${resource}-${direction}-${type}`, true); + } + } + + private addResource(resource: string, frame?: string | number): void { + const sprite = new Sprite(this.scene, 0, 0, resource, frame); + + this.add(sprite); + + this.getAnimations(resource).forEach(animation => { + this.scene.anims.create(animation); + }); + + this.scene.sys.updateList.add(sprite); + this.sprites.set(resource, sprite); + } + + private getAnimations(resource: string): Phaser.Types.Animations.Animation[] { + return [ + { + key: `${resource}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [1]}), + frameRate: 10, + repeat: 1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [4]}), + frameRate: 10, + repeat: 1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [7]}), + frameRate: 10, + repeat: 1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [10]}), + frameRate: 10, + repeat: 1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [0, 1, 2]}), + frameRate: 15, + repeat: -1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [3, 4, 5]}), + frameRate: 15, + repeat: -1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [6, 7, 8]}), + frameRate: 15, + repeat: -1 + }, + { + key: `${resource}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`, + frames: this.scene.anims.generateFrameNumbers(resource, {frames: [9, 10, 11]}), + frameRate: 15, + repeat: -1 + } + ] + } + + private getBody(): Phaser.Physics.Arcade.Body { + const body = this.body; + + if (!(body instanceof Phaser.Physics.Arcade.Body)) { + throw new Error('Container does not have arcade body'); + } + + return body; + } + + public destroy(): void { + for (const sprite of this.sprites.values()) { + if (this.scene) { + this.scene.sys.updateList.remove(sprite); + } + } + + if (this.scene) { + this.scene.game.events.removeListener('step', this.step.bind(this)); + } + + super.destroy(); + } +} diff --git a/front/src/Phaser/Companion/CompanionTextures.ts b/front/src/Phaser/Companion/CompanionTextures.ts new file mode 100644 index 00000000..84eaf38f --- /dev/null +++ b/front/src/Phaser/Companion/CompanionTextures.ts @@ -0,0 +1,14 @@ +export interface CompanionResourceDescriptionInterface { + name: string, + img: string, + behaviour: "dog" | "cat" +} + +export const COMPANION_RESOURCES: CompanionResourceDescriptionInterface[] = [ + { name: "dog1", img: "resources/characters/pipoya/Dog 01-1.png", behaviour: "dog" }, + { name: "dog2", img: "resources/characters/pipoya/Dog 01-2.png", behaviour: "dog" }, + { name: "dog3", img: "resources/characters/pipoya/Dog 01-3.png", behaviour: "dog" }, + { name: "cat1", img: "resources/characters/pipoya/Cat 01-1.png", behaviour: "cat" }, + { name: "cat2", img: "resources/characters/pipoya/Cat 01-2.png", behaviour: "cat" }, + { name: "cat3", img: "resources/characters/pipoya/Cat 01-3.png", behaviour: "cat" }, +] diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts new file mode 100644 index 00000000..7023a34d --- /dev/null +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -0,0 +1,30 @@ +import LoaderPlugin = Phaser.Loader.LoaderPlugin; +import { TextureError } from "../../Exception/TextureError"; +import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures"; + +export const loadAll = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => { + const resources = COMPANION_RESOURCES; + + resources.forEach((resource: CompanionResourceDescriptionInterface) => { + loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); + }); + + return resources; +} + +export const lazyLoadResource = (loader: LoaderPlugin, name: string): Promise => { + const resource = COMPANION_RESOURCES.find(item => item.name === name); + + if (typeof resource === 'undefined') { + throw new TextureError(`Texture '${name}' not found!`); + } + + if (loader.textureManager.exists(resource.name)) { + return Promise.resolve(resource.name); + } + + return new Promise(resolve => { + loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); + loader.once(`filecomplete-spritesheet-${resource.name}`, () => resolve(resource.name)); + }); +} diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index 64ba56d0..b7a2f7b4 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -2,7 +2,7 @@ import {PlayerAnimationDirections} from "./Animation"; import {GameScene} from "../Game/GameScene"; import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager"; import {Character} from "../Entity/Character"; - +import {Companion} from "../Companion/Companion"; export const hasMovedEventName = "hasMoved"; export interface CurrentGamerInterface extends Character{ @@ -13,6 +13,7 @@ export interface CurrentGamerInterface extends Character{ export class Player extends Character implements CurrentGamerInterface { private previousDirection: string = PlayerAnimationDirections.Down; private wasMoving: boolean = false; + private companion?: Companion; constructor( Scene: GameScene, @@ -28,6 +29,20 @@ export class Player extends Character implements CurrentGamerInterface { //the current player model should be push away by other players to prevent conflict this.getBody().setImmovable(false); + + this.addCompanion(); + } + + addCompanion(): void { + this.companion = new Companion(this.scene, this.x, this.y); + } + + move(x: number, y: number) { + super.move(x, y); + + if (this.companion) { + this.companion.setTarget(this.x, this.y); + } } moveUser(delta: number): void { From 5a91e1558088ecd2c2e1c8914e5c48f8d6e49c59 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Thu, 1 Apr 2021 18:51:51 +0200 Subject: [PATCH 02/20] add companion to remote player --- front/src/Phaser/Companion/Companion.ts | 47 ++++++++++++++----------- front/src/Phaser/Entity/Character.ts | 16 +++++++++ front/src/Phaser/Entity/RemotePlayer.ts | 4 +++ front/src/Phaser/Player/Player.ts | 16 --------- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index ab9b8be8..065b3a8d 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -8,18 +8,19 @@ export class Companion extends Container { private delta: number; private invisible: boolean; - private target: { x: number, y: number }; + private stepListener: Function; + private target: { x: number, y: number, direction: PlayerAnimationDirections }; constructor( scene: Phaser.Scene, x: number, y: number ) { - super(scene, x, y); + super(scene, x + 8, y + 8); this.delta = 0; this.invisible = true; - this.target = { x, y }; + this.target = { x, y, direction: PlayerAnimationDirections.Down }; this.sprites = new Map(); const animal = ["dog1", "dog2", "dog3", "cat1", "cat2", "cat3"]; @@ -40,19 +41,21 @@ export class Companion extends Container { this.setDepth(-1); - scene.game.events.addListener('step', this.step.bind(this)); + this.stepListener = this.step.bind(this); + + scene.game.events.addListener('step', this.stepListener); scene.add.existing(this); } - public setTarget(x: number, y: number) { - this.target = { x, y }; + public setTarget(x: number, y: number, direction: PlayerAnimationDirections) { + this.target = { x, y, direction }; } private step(time: any, delta: any) { if (typeof this.target === 'undefined') return; this.delta += delta; - if (this.delta < 256) { + if (this.delta < 128) { return; } this.delta = 0; @@ -63,10 +66,12 @@ export class Companion extends Container { let direction: PlayerAnimationDirections; let type: PlayerAnimationTypes; - const distance = Math.sqrt(Math.pow(Math.abs(xDist), 2) + Math.pow(Math.abs(yDist), 2)); + const distance = Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2)); if (distance < 16) { type = PlayerAnimationTypes.Idle; + direction = this.target.direction; + this.getBody().stop(); } else { type = PlayerAnimationTypes.Walk; @@ -76,22 +81,22 @@ export class Companion extends Container { const speed = 256; this.getBody().setVelocity(Math.min(Math.abs(xDist * 2), speed) * xDir, Math.min(Math.abs(yDist * 2), speed) * yDir); - } - if (Math.abs(xDist) > Math.abs(yDist)) { - if (xDist < 0) { - direction = PlayerAnimationDirections.Left; + if (Math.abs(xDist) > Math.abs(yDist)) { + if (xDist < 0) { + direction = PlayerAnimationDirections.Left; + } else { + direction = PlayerAnimationDirections.Right; + } } else { - direction = PlayerAnimationDirections.Right; - } - } else { - if (yDist < 0) { - direction = PlayerAnimationDirections.Up; - } else { - direction = PlayerAnimationDirections.Down; + if (yDist < 0) { + direction = PlayerAnimationDirections.Up; + } else { + direction = PlayerAnimationDirections.Down; + } } } - + this.setDepth(this.y); this.playAnimation(direction, type); } @@ -188,7 +193,7 @@ export class Companion extends Container { } if (this.scene) { - this.scene.game.events.removeListener('step', this.step.bind(this)); + this.scene.game.events.removeListener('step', this.stepListener); } super.destroy(); diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 797616f8..352494f8 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -4,6 +4,7 @@ import BitmapText = Phaser.GameObjects.BitmapText; import Container = Phaser.GameObjects.Container; import Sprite = Phaser.GameObjects.Sprite; import {TextureError} from "../../Exception/TextureError"; +import {Companion} from "../Companion/Companion"; interface AnimationData { key: string; @@ -21,6 +22,7 @@ export abstract class Character extends Container { private lastDirection: PlayerAnimationDirections = PlayerAnimationDirections.Down; //private teleportation: Sprite; private invisible: boolean; + public companion?: Companion; constructor(scene: Phaser.Scene, x: number, @@ -67,6 +69,12 @@ export abstract class Character extends Container { this.setDepth(-1); this.playAnimation(direction, moving); + + this.addCompanion(); + } + + private addCompanion(): void { + this.companion = new Companion(this.scene, this.x, this.y); } public addTextures(textures: string[], frame?: string | number): void { @@ -189,6 +197,10 @@ export abstract class Character extends Container { } this.setDepth(this.y); + + if (this.companion) { + this.companion.setTarget(this.x, this.y, this.lastDirection); + } } stop(){ @@ -215,5 +227,9 @@ export abstract class Character extends Container { } super.destroy(); this.playerName.destroy(); + + if (this.companion) { + this.companion.destroy(); + } } } diff --git a/front/src/Phaser/Entity/RemotePlayer.ts b/front/src/Phaser/Entity/RemotePlayer.ts index a6bd4f40..4fe18fc6 100644 --- a/front/src/Phaser/Entity/RemotePlayer.ts +++ b/front/src/Phaser/Entity/RemotePlayer.ts @@ -31,5 +31,9 @@ export class RemotePlayer extends Character { this.setY(position.y); this.setDepth(position.y); //this is to make sure the perspective (player models closer the bottom of the screen will appear in front of models nearer the top of the screen). + + if (this.companion) { + this.companion.setTarget(position.x, position.y, position.direction as PlayerAnimationDirections); + } } } diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index b7a2f7b4..ac8942a5 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -2,7 +2,6 @@ import {PlayerAnimationDirections} from "./Animation"; import {GameScene} from "../Game/GameScene"; import {UserInputEvent, UserInputManager} from "../UserInput/UserInputManager"; import {Character} from "../Entity/Character"; -import {Companion} from "../Companion/Companion"; export const hasMovedEventName = "hasMoved"; export interface CurrentGamerInterface extends Character{ @@ -13,7 +12,6 @@ export interface CurrentGamerInterface extends Character{ export class Player extends Character implements CurrentGamerInterface { private previousDirection: string = PlayerAnimationDirections.Down; private wasMoving: boolean = false; - private companion?: Companion; constructor( Scene: GameScene, @@ -29,20 +27,6 @@ export class Player extends Character implements CurrentGamerInterface { //the current player model should be push away by other players to prevent conflict this.getBody().setImmovable(false); - - this.addCompanion(); - } - - addCompanion(): void { - this.companion = new Companion(this.scene, this.x, this.y); - } - - move(x: number, y: number) { - super.move(x, y); - - if (this.companion) { - this.companion.setTarget(this.x, this.y); - } } moveUser(delta: number): void { From 2ad712807ba13e9f32d974a284ba2961fb3b15ae Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 17:14:34 +0200 Subject: [PATCH 03/20] add companion only on local player --- front/src/Phaser/Companion/Companion.ts | 70 ++++++++++++++++--------- front/src/Phaser/Entity/Character.ts | 4 +- front/src/Phaser/Player/Player.ts | 7 +++ 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 065b3a8d..60e58995 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -3,14 +3,25 @@ import Container = Phaser.GameObjects.Container; import { lazyLoadResource } from "./CompanionTexturesLoadingManager"; import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation"; +export interface CompanionStatus { + x: number; + y: number; + name: string; + moving: boolean; + direction: PlayerAnimationDirections; +} + export class Companion extends Container { public sprites: Map; private delta: number; private invisible: boolean; - private stepListener: Function; private target: { x: number, y: number, direction: PlayerAnimationDirections }; + private companionName: string; + private direction: PlayerAnimationDirections; + private animationType: PlayerAnimationTypes; + constructor( scene: Phaser.Scene, x: number, @@ -18,15 +29,22 @@ export class Companion extends Container { ) { super(scene, x + 8, y + 8); + this.sprites = new Map(); + this.delta = 0; this.invisible = true; this.target = { x, y, direction: PlayerAnimationDirections.Down }; - this.sprites = new Map(); + this.direction = PlayerAnimationDirections.Down; + this.animationType = PlayerAnimationTypes.Idle; + + // select random animal const animal = ["dog1", "dog2", "dog3", "cat1", "cat2", "cat3"]; const random = Math.floor(Math.random() * animal.length); - lazyLoadResource(this.scene.load, animal[random]).then(resource => { + this.companionName = animal[random]; + + lazyLoadResource(this.scene.load, this.companionName).then(resource => { this.addResource(resource); this.invisible = false; }) @@ -34,16 +52,13 @@ export class Companion extends Container { this.scene.physics.world.enableBody(this); this.getBody().setImmovable(true); - this.getBody().setCollideWorldBounds(true); + this.getBody().setCollideWorldBounds(false); this.setSize(16, 16); this.getBody().setSize(16, 16); this.getBody().setOffset(0, 8); this.setDepth(-1); - this.stepListener = this.step.bind(this); - - scene.game.events.addListener('step', this.stepListener); scene.add.existing(this); } @@ -51,7 +66,7 @@ export class Companion extends Container { this.target = { x, y, direction }; } - private step(time: any, delta: any) { + public step(delta: number) { if (typeof this.target === 'undefined') return; this.delta += delta; @@ -63,18 +78,15 @@ export class Companion extends Container { const xDist = this.target.x - this.x; const yDist = this.target.y - this.y; - let direction: PlayerAnimationDirections; - let type: PlayerAnimationTypes; + const distance = Math.pow(xDist, 2) + Math.pow(yDist, 2); - const distance = Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2)); - - if (distance < 16) { - type = PlayerAnimationTypes.Idle; - direction = this.target.direction; + if (distance < 576) { // 24^2 + this.animationType = PlayerAnimationTypes.Idle; + this.direction = this.target.direction; this.getBody().stop(); } else { - type = PlayerAnimationTypes.Walk; + this.animationType = PlayerAnimationTypes.Walk; const xDir = xDist / Math.max(Math.abs(xDist), 1); const yDir = yDist / Math.max(Math.abs(yDist), 1); @@ -84,21 +96,33 @@ export class Companion extends Container { if (Math.abs(xDist) > Math.abs(yDist)) { if (xDist < 0) { - direction = PlayerAnimationDirections.Left; + this.direction = PlayerAnimationDirections.Left; } else { - direction = PlayerAnimationDirections.Right; + this.direction = PlayerAnimationDirections.Right; } } else { if (yDist < 0) { - direction = PlayerAnimationDirections.Up; + this.direction = PlayerAnimationDirections.Up; } else { - direction = PlayerAnimationDirections.Down; + this.direction = PlayerAnimationDirections.Down; } } } this.setDepth(this.y); - this.playAnimation(direction, type); + this.playAnimation(this.direction, this.animationType); + } + + public getStatus(): CompanionStatus { + const { x, y, direction, animationType, companionName } = this; + + return { + x, + y, + direction, + moving: animationType === PlayerAnimationTypes.Walk, + name: companionName + } } private playAnimation(direction: PlayerAnimationDirections, type: PlayerAnimationTypes): void { @@ -192,10 +216,6 @@ export class Companion extends Container { } } - if (this.scene) { - this.scene.game.events.removeListener('step', this.stepListener); - } - super.destroy(); } } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 352494f8..f329192c 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -69,11 +69,9 @@ export abstract class Character extends Container { this.setDepth(-1); this.playAnimation(direction, moving); - - this.addCompanion(); } - private addCompanion(): void { + public addCompanion(): void { this.companion = new Companion(this.scene, this.x, this.y); } diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index ac8942a5..af63ddb3 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -27,6 +27,8 @@ export class Player extends Character implements CurrentGamerInterface { //the current player model should be push away by other players to prevent conflict this.getBody().setImmovable(false); + + this.addCompanion(); } moveUser(delta: number): void { @@ -58,6 +60,11 @@ export class Player extends Character implements CurrentGamerInterface { direction = PlayerAnimationDirections.Right; moving = true; } + + if (this.companion) { + this.companion.step(delta); + } + if (x !== 0 || y !== 0) { this.move(x, y); this.emit(hasMovedEventName, {moving, direction, x: this.x, y: this.y}); From c07079051a39d0cddf40e1d4846d8490840630a2 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 21:21:11 +0200 Subject: [PATCH 04/20] transmit companion to remote players --- back/src/Model/GameRoom.ts | 3 ++- back/src/Model/User.ts | 5 +++-- back/src/Services/SocketManager.ts | 2 ++ front/src/Connexion/ConnectionManager.ts | 6 +++--- front/src/Connexion/ConnexionModels.ts | 4 +++- front/src/Connexion/LocalUserStore.ts | 8 ++++++++ front/src/Connexion/RoomConnection.ts | 11 ++++++++-- front/src/Phaser/Companion/Companion.ts | 20 ++++++++----------- front/src/Phaser/Entity/Character.ts | 4 ++-- front/src/Phaser/Entity/RemotePlayer.ts | 9 +++++++-- front/src/Phaser/Game/AddPlayerInterface.ts | 1 + front/src/Phaser/Game/GameManager.ts | 5 +++++ front/src/Phaser/Game/GameScene.ts | 16 ++++++++++----- front/src/Phaser/Player/Player.ts | 11 +++++----- messages/protos/messages.proto | 7 +++++++ pusher/src/Controller/IoSocketController.ts | 12 ++++++++++- .../src/Model/Websocket/ExSocketInterface.ts | 2 ++ pusher/src/Model/Zone.ts | 8 +++++--- pusher/src/Services/SocketManager.ts | 2 ++ 19 files changed, 96 insertions(+), 40 deletions(-) diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index 6a592ed0..430dbc48 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -110,7 +110,8 @@ export class GameRoom { socket, joinRoomMessage.getTagList(), joinRoomMessage.getName(), - ProtobufUtils.toCharacterLayerObjects(joinRoomMessage.getCharacterlayerList()) + ProtobufUtils.toCharacterLayerObjects(joinRoomMessage.getCharacterlayerList()), + joinRoomMessage.getCompanion() ); this.nextUserId++; this.users.set(user.id, user); diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index 51a1a617..370781e5 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -4,7 +4,7 @@ import {Zone} from "_Model/Zone"; import {Movable} from "_Model/Movable"; import {PositionNotifier} from "_Model/PositionNotifier"; import {ServerDuplexStream} from "grpc"; -import {BatchMessage, PusherToBackMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb"; +import {BatchMessage, Companion, PusherToBackMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb"; import {CharacterLayer} from "_Model/Websocket/CharacterLayer"; export type UserSocket = ServerDuplexStream; @@ -23,7 +23,8 @@ export class User implements Movable { public readonly socket: UserSocket, public readonly tags: string[], public readonly name: string, - public readonly characterLayers: CharacterLayer[] + public readonly characterLayers: CharacterLayer[], + public readonly companion?: Companion ) { this.listenedZones = new Set(); diff --git a/back/src/Services/SocketManager.ts b/back/src/Services/SocketManager.ts index c03f4773..166622f9 100644 --- a/back/src/Services/SocketManager.ts +++ b/back/src/Services/SocketManager.ts @@ -325,6 +325,7 @@ export class SocketManager { userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); userJoinedZoneMessage.setFromzone(this.toProtoZone(fromZone)); + userJoinedZoneMessage.setCompanion(thing.companion); const subMessage = new SubToPusherMessage(); subMessage.setUserjoinedzonemessage(userJoinedZoneMessage); @@ -634,6 +635,7 @@ export class SocketManager { userJoinedMessage.setName(thing.name); userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); + userJoinedMessage.setCompanion(thing.companion); const subMessage = new SubToPusherMessage(); subMessage.setUserjoinedzonemessage(userJoinedMessage); diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index ed920aa0..e1e0db0a 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -88,9 +88,9 @@ class ConnectionManager { this.localUser = new LocalUser('', 'test', []); } - public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface): Promise { + public connectToRoomSocket(roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, companion: string|null): Promise { return new Promise((resolve, reject) => { - const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport); + const connection = new RoomConnection(this.localUser.jwtToken, roomId, name, characterLayers, position, viewport, companion); connection.onConnectError((error: object) => { console.log('An error occurred while connecting to socket server. Retrying'); reject(error); @@ -111,7 +111,7 @@ class ConnectionManager { this.reconnectingTimeout = setTimeout(() => { //todo: allow a way to break recursion? //todo: find a way to avoid recursive function. Otherwise, the call stack will grow indefinitely. - this.connectToRoomSocket(roomId, name, characterLayers, position, viewport).then((connection) => resolve(connection)); + this.connectToRoomSocket(roomId, name, characterLayers, position, viewport, companion).then((connection) => resolve(connection)); }, 4000 + Math.floor(Math.random() * 2000) ); }); }); diff --git a/front/src/Connexion/ConnexionModels.ts b/front/src/Connexion/ConnexionModels.ts index 519afcd3..477e86e3 100644 --- a/front/src/Connexion/ConnexionModels.ts +++ b/front/src/Connexion/ConnexionModels.ts @@ -47,6 +47,7 @@ export interface MessageUserPositionInterface { name: string; characterLayers: BodyResourceDescriptionInterface[]; position: PointInterface; + companion: string|null; } export interface MessageUserMovedInterface { @@ -58,7 +59,8 @@ export interface MessageUserJoined { userId: number; name: string; characterLayers: BodyResourceDescriptionInterface[]; - position: PointInterface + position: PointInterface; + companion: string|null; } export interface PositionInterface { diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index 702df561..4989a9ea 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -4,6 +4,7 @@ const playerNameKey = 'playerName'; const selectedPlayerKey = 'selectedPlayer'; const customCursorPositionKey = 'customCursorPosition'; const characterLayersKey = 'characterLayers'; +const companionKey = 'companion'; const gameQualityKey = 'gameQuality'; const videoQualityKey = 'videoQuality'; const audioPlayerVolumeKey = 'audioVolume'; @@ -47,6 +48,13 @@ class LocalUserStore { return JSON.parse(localStorage.getItem(characterLayersKey) || "null"); } + setCompanion(companion: string): void { + localStorage.setItem(companionKey, companion); + } + getCompanion(): string|null { + return localStorage.getItem(companionKey); + } + setGameQualityValue(value: number): void { localStorage.setItem(gameQualityKey, '' + value); } diff --git a/front/src/Connexion/RoomConnection.ts b/front/src/Connexion/RoomConnection.ts index 584dae06..391d227d 100644 --- a/front/src/Connexion/RoomConnection.ts +++ b/front/src/Connexion/RoomConnection.ts @@ -66,7 +66,7 @@ export class RoomConnection implements RoomConnection { * @param token A JWT token containing the UUID of the user * @param roomId The ID of the room in the form "_/[instance]/[map_url]" or "@/[org]/[event]/[map]" */ - public constructor(token: string|null, roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface) { + public constructor(token: string|null, roomId: string, name: string, characterLayers: string[], position: PositionInterface, viewport: ViewportInterface, companion: string|null) { let url = API_URL.replace('http://', 'ws://').replace('https://', 'wss://'); url += '/room'; url += '?roomId='+(roomId ?encodeURIComponent(roomId):''); @@ -81,6 +81,10 @@ export class RoomConnection implements RoomConnection { url += '&bottom='+Math.floor(viewport.bottom); url += '&left='+Math.floor(viewport.left); url += '&right='+Math.floor(viewport.right); + + if (typeof companion === 'string') { + url += '&companion='+encodeURIComponent(companion); + } if (RoomConnection.websocketFactory) { this.socket = RoomConnection.websocketFactory(url); @@ -316,11 +320,14 @@ export class RoomConnection implements RoomConnection { } }) + const companion = message.getCompanion(); + return { userId: message.getUserid(), name: message.getName(), characterLayers, - position: ProtobufClientUtils.toPointInterface(position) + position: ProtobufClientUtils.toPointInterface(position), + companion: companion ? companion.getName() : null } } diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 60e58995..196da09e 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -22,11 +22,7 @@ export class Companion extends Container { private direction: PlayerAnimationDirections; private animationType: PlayerAnimationTypes; - constructor( - scene: Phaser.Scene, - x: number, - y: number - ) { + constructor(scene: Phaser.Scene, x: number, y: number, name: string) { super(scene, x + 8, y + 8); this.sprites = new Map(); @@ -38,11 +34,7 @@ export class Companion extends Container { this.direction = PlayerAnimationDirections.Down; this.animationType = PlayerAnimationTypes.Idle; - // select random animal - const animal = ["dog1", "dog2", "dog3", "cat1", "cat2", "cat3"]; - const random = Math.floor(Math.random() * animal.length); - - this.companionName = animal[random]; + this.companionName = name; lazyLoadResource(this.scene.load, this.companionName).then(resource => { this.addResource(resource); @@ -59,14 +51,16 @@ export class Companion extends Container { this.setDepth(-1); - scene.add.existing(this); + this.scene.events.addListener('update', this.step, this); + + this.scene.add.existing(this); } public setTarget(x: number, y: number, direction: PlayerAnimationDirections) { this.target = { x, y, direction }; } - public step(delta: number) { + public step(time: number, delta: number) { if (typeof this.target === 'undefined') return; this.delta += delta; @@ -216,6 +210,8 @@ export class Companion extends Container { } } + this.scene.events.removeListener('update', this.step, this); + super.destroy(); } } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index f329192c..eb8e45fd 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -71,8 +71,8 @@ export abstract class Character extends Container { this.playAnimation(direction, moving); } - public addCompanion(): void { - this.companion = new Companion(this.scene, this.x, this.y); + public addCompanion(name: string): void { + this.companion = new Companion(this.scene, this.x, this.y, name); } public addTextures(textures: string[], frame?: string | number): void { diff --git a/front/src/Phaser/Entity/RemotePlayer.ts b/front/src/Phaser/Entity/RemotePlayer.ts index 4fe18fc6..b405d8df 100644 --- a/front/src/Phaser/Entity/RemotePlayer.ts +++ b/front/src/Phaser/Entity/RemotePlayer.ts @@ -17,12 +17,17 @@ export class RemotePlayer extends Character { name: string, texturesPromise: Promise, direction: PlayerAnimationDirections, - moving: boolean + moving: boolean, + companion: string|null ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1); - + //set data this.userId = userId; + + if (typeof companion === 'string') { + this.addCompanion(companion); + } } updatePosition(position: PointInterface): void { diff --git a/front/src/Phaser/Game/AddPlayerInterface.ts b/front/src/Phaser/Game/AddPlayerInterface.ts index 0edf197e..96762a66 100644 --- a/front/src/Phaser/Game/AddPlayerInterface.ts +++ b/front/src/Phaser/Game/AddPlayerInterface.ts @@ -6,4 +6,5 @@ export interface AddPlayerInterface { name: string; characterLayers: BodyResourceDescriptionInterface[]; position: PointInterface; + companion: string|null; } diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 8751796f..fbe5102c 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -21,12 +21,14 @@ export interface HasMovedEvent { export class GameManager { private playerName: string|null; private characterLayers: string[]|null; + private companion: string|null; private startRoom!:Room; currentGameSceneName: string|null = null; constructor() { this.playerName = localUserStore.getName(); this.characterLayers = localUserStore.getCharacterLayers(); + this.companion = localUserStore.getCompanion(); } public async init(scenePlugin: Phaser.Scenes.ScenePlugin): Promise { @@ -63,6 +65,9 @@ export class GameManager { return this.characterLayers; } + getCompanion(): string|null { + return this.companion; + } public async loadMap(room: Room, scenePlugin: Phaser.Scenes.ScenePlugin): Promise { const roomID = room.id; diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 51388169..222f7ed5 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -159,6 +159,7 @@ export class GameScene extends ResizableScene implements CenterListener { private openChatIcon!: OpenChatIcon; private playerName!: string; private characterLayers!: string[]; + private companion!: string|null; private messageSubscription: Subscription|null = null; private popUpElements : Map = new Map(); @@ -335,7 +336,7 @@ export class GameScene extends ResizableScene implements CenterListener { } this.playerName = playerName; this.characterLayers = gameManager.getCharacterLayers(); - + this.companion = gameManager.getCompanion(); //initalise map this.Map = this.add.tilemap(this.MapUrlFile); @@ -459,7 +460,9 @@ export class GameScene extends ResizableScene implements CenterListener { top: camera.scrollY, right: camera.scrollX + camera.width, bottom: camera.scrollY + camera.height, - }).then((onConnect: OnConnectInterface) => { + }, + this.companion + ).then((onConnect: OnConnectInterface) => { this.connection = onConnect.connection; this.connection.onUserJoins((message: MessageUserJoined) => { @@ -467,7 +470,8 @@ export class GameScene extends ResizableScene implements CenterListener { userId: message.userId, characterLayers: message.characterLayers, name: message.name, - position: message.position + position: message.position, + companion: message.companion } this.addPlayer(userMessage); }); @@ -1019,7 +1023,8 @@ ${escapedMessage} texturesPromise, PlayerAnimationDirections.Down, false, - this.userInputManager + this.userInputManager, + this.companion ); }catch (err){ if(err instanceof TextureError) { @@ -1211,7 +1216,8 @@ ${escapedMessage} addPlayerData.name, texturesPromise, addPlayerData.position.direction as PlayerAnimationDirections, - addPlayerData.position.moving + addPlayerData.position.moving, + addPlayerData.companion ); this.MapPlayers.add(player); this.MapPlayersByKey.set(player.userId, player); diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index af63ddb3..d018a41f 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -21,14 +21,17 @@ export class Player extends Character implements CurrentGamerInterface { texturesPromise: Promise, direction: PlayerAnimationDirections, moving: boolean, - private userInputManager: UserInputManager + private userInputManager: UserInputManager, + companion: string|null ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1); //the current player model should be push away by other players to prevent conflict this.getBody().setImmovable(false); - this.addCompanion(); + if (typeof companion === 'string') { + this.addCompanion(companion); + } } moveUser(delta: number): void { @@ -61,10 +64,6 @@ export class Player extends Character implements CurrentGamerInterface { moving = true; } - if (this.companion) { - this.companion.step(delta); - } - if (x !== 0 || y !== 0) { this.move(x, y); this.emit(hasMovedEventName, {moving, direction, x: this.x, y: this.y}); diff --git a/messages/protos/messages.proto b/messages/protos/messages.proto index cc23ed24..eee3be86 100644 --- a/messages/protos/messages.proto +++ b/messages/protos/messages.proto @@ -36,6 +36,10 @@ message CharacterLayerMessage { string name = 2; } +message Companion { + string name = 1; +} + /*********** CLIENT TO SERVER MESSAGES *************/ message PingMessage { @@ -141,6 +145,7 @@ message UserJoinedMessage { string name = 2; repeated CharacterLayerMessage characterLayers = 3; PositionMessage position = 4; + Companion companion = 5; } message UserLeftMessage { @@ -243,6 +248,7 @@ message JoinRoomMessage { string roomId = 5; repeated string tag = 6; string IPAddress = 7; + Companion companion = 8; } message UserJoinedZoneMessage { @@ -251,6 +257,7 @@ message UserJoinedZoneMessage { repeated CharacterLayerMessage characterLayers = 3; PositionMessage position = 4; Zone fromZone = 5; + Companion companion = 6; } message UserLeftZoneMessage { diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 85a80e11..55a8e032 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -12,7 +12,7 @@ import { WebRtcSignalToServerMessage, PlayGlobalMessage, ReportPlayerMessage, - QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage + QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage, Companion } from "../Messages/generated/messages_pb"; import {UserMovesMessage} from "../Messages/generated/messages_pb"; import {TemplatedApp} from "uWebSockets.js" @@ -138,6 +138,14 @@ export class IoSocketController { const left = Number(query.left); const right = Number(query.right); const name = query.name; + + let companion: Companion|undefined = undefined; + + if (typeof query.companion === 'string') { + companion = new Companion(); + companion.setName(query.companion); + } + if (typeof name !== 'string') { throw new Error('Expecting name'); } @@ -221,6 +229,7 @@ export class IoSocketController { IPAddress, roomId, name, + companion, characterLayers: characterLayerObjs, messages: memberMessages, tags: memberTags, @@ -350,6 +359,7 @@ export class IoSocketController { client.tags = ws.tags; client.textures = ws.textures; client.characterLayers = ws.characterLayers; + client.companion = ws.companion; client.roomId = ws.roomId; client.listenedZones = new Set(); return client; diff --git a/pusher/src/Model/Websocket/ExSocketInterface.ts b/pusher/src/Model/Websocket/ExSocketInterface.ts index 56e7e5ca..135c6f10 100644 --- a/pusher/src/Model/Websocket/ExSocketInterface.ts +++ b/pusher/src/Model/Websocket/ExSocketInterface.ts @@ -3,6 +3,7 @@ import {Identificable} from "./Identificable"; import {ViewportInterface} from "_Model/Websocket/ViewportMessage"; import { BatchMessage, + Companion, PusherToBackMessage, ServerToClientMessage, SubMessage @@ -29,6 +30,7 @@ export interface ExSocketInterface extends WebSocket, Identificable { characterLayers: CharacterLayer[]; position: PointInterface; viewport: ViewportInterface; + companion?: Companion; /** * Pushes an event that will be sent in the next batch of events */ diff --git a/pusher/src/Model/Zone.ts b/pusher/src/Model/Zone.ts index 12d27ff3..a54481a5 100644 --- a/pusher/src/Model/Zone.ts +++ b/pusher/src/Model/Zone.ts @@ -5,7 +5,8 @@ import { CharacterLayerMessage, GroupLeftZoneMessage, GroupUpdateMessage, GroupUpdateZoneMessage, PointMessage, PositionMessage, UserJoinedMessage, UserJoinedZoneMessage, UserLeftZoneMessage, UserMovedMessage, - ZoneMessage + ZoneMessage, + Companion } from "../Messages/generated/messages_pb"; import * as messages_pb from "../Messages/generated/messages_pb"; import {ClientReadableStream} from "grpc"; @@ -30,7 +31,7 @@ export type MovesCallback = (thing: Movable, position: PositionInterface, listen export type LeavesCallback = (thing: Movable, listener: User) => void;*/ export class UserDescriptor { - private constructor(public readonly userId: number, private name: string, private characterLayers: CharacterLayerMessage[], private position: PositionMessage) { + private constructor(public readonly userId: number, private name: string, private characterLayers: CharacterLayerMessage[], private position: PositionMessage, private companion?: Companion) { if (!Number.isInteger(this.userId)) { throw new Error('UserDescriptor.userId is not an integer: '+this.userId); } @@ -41,7 +42,7 @@ export class UserDescriptor { if (position === undefined) { throw new Error('Missing position'); } - return new UserDescriptor(message.getUserid(), message.getName(), message.getCharacterlayersList(), position); + return new UserDescriptor(message.getUserid(), message.getName(), message.getCharacterlayersList(), position, message.getCompanion()); } public update(userMovedMessage: UserMovedMessage) { @@ -59,6 +60,7 @@ export class UserDescriptor { userJoinedMessage.setName(this.name); userJoinedMessage.setCharacterlayersList(this.characterLayers); userJoinedMessage.setPosition(this.position); + userJoinedMessage.setCompanion(this.companion) return userJoinedMessage; } diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 9b698e38..d555a59c 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -153,6 +153,8 @@ export class SocketManager implements ZoneEventListener { joinRoomMessage.setName(client.name); joinRoomMessage.setPositionmessage(ProtobufUtils.toPositionMessage(client.position)); joinRoomMessage.setTagList(client.tags); + joinRoomMessage.setCompanion(client.companion); + for (const characterLayer of client.characterLayers) { const characterLayerMessage = new CharacterLayerMessage(); characterLayerMessage.setName(characterLayer.name); From fc3a503bcf1e4c35847cc89077a96adecb4fb3a9 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 21:26:24 +0200 Subject: [PATCH 05/20] don't fail if companion texture is not found --- front/src/Phaser/Companion/Companion.ts | 10 ++++++---- .../CompanionTexturesLoadingManager.ts | 20 +++++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 196da09e..407b7326 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -36,10 +36,12 @@ export class Companion extends Container { this.companionName = name; - lazyLoadResource(this.scene.load, this.companionName).then(resource => { - this.addResource(resource); - this.invisible = false; - }) + lazyLoadResource(this.scene.load, this.companionName) + .then(resource => { + this.addResource(resource); + this.invisible = false; + }) + .catch(error => console.error(error)); this.scene.physics.world.enableBody(this); diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index 7023a34d..126af219 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -13,17 +13,17 @@ export const loadAll = (loader: LoaderPlugin): CompanionResourceDescriptionInter } export const lazyLoadResource = (loader: LoaderPlugin, name: string): Promise => { - const resource = COMPANION_RESOURCES.find(item => item.name === name); + return new Promise((resolve, reject) => { + const resource = COMPANION_RESOURCES.find(item => item.name === name); - if (typeof resource === 'undefined') { - throw new TextureError(`Texture '${name}' not found!`); - } - - if (loader.textureManager.exists(resource.name)) { - return Promise.resolve(resource.name); - } - - return new Promise(resolve => { + if (typeof resource === 'undefined') { + return reject(`Texture '${name}' not found!`); + } + + if (loader.textureManager.exists(resource.name)) { + return resolve(resource.name); + } + loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); loader.once(`filecomplete-spritesheet-${resource.name}`, () => resolve(resource.name)); }); From e4d324e5fab5df40e621467d2fcc2cf63d4d45b3 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 21:26:42 +0200 Subject: [PATCH 06/20] removed unused import --- front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index 126af219..bc260c69 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -1,5 +1,4 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin; -import { TextureError } from "../../Exception/TextureError"; import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures"; export const loadAll = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => { From 4cfce15695fef93e02799575cb7e4822f7c5d7c4 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 21:29:45 +0200 Subject: [PATCH 07/20] only remove listener if scene was not already destroyed --- front/src/Phaser/Companion/Companion.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 407b7326..2d11110e 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -212,7 +212,9 @@ export class Companion extends Container { } } - this.scene.events.removeListener('update', this.step, this); + if (this.scene) { + this.scene.events.removeListener('update', this.step, this); + } super.destroy(); } From 52303c0bd69612e649acfe9a95523736e31237e2 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 23:00:51 +0200 Subject: [PATCH 08/20] added select companion scene --- front/src/Connexion/LocalUserStore.ts | 9 +- .../CompanionTexturesLoadingManager.ts | 12 +- front/src/Phaser/Game/GameManager.ts | 8 + .../src/Phaser/Login/SelectCompanionScene.ts | 248 ++++++++++++++++++ front/src/index.ts | 3 +- 5 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 front/src/Phaser/Login/SelectCompanionScene.ts diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index 4989a9ea..a766f5dc 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -48,11 +48,14 @@ class LocalUserStore { return JSON.parse(localStorage.getItem(characterLayersKey) || "null"); } - setCompanion(companion: string): void { - localStorage.setItem(companionKey, companion); + setCompanion(companion: string|null): void { + return localStorage.setItem(companionKey, JSON.stringify(companion)); } getCompanion(): string|null { - return localStorage.getItem(companionKey); + return JSON.parse(localStorage.getItem(companionKey) || "null"); + } + wasCompanionSet(): boolean { + return localStorage.getItem(companionKey) ? true : false; } setGameQualityValue(value: number): void { diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index bc260c69..b7859a70 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -1,14 +1,16 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin; import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures"; -export const loadAll = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => { - const resources = COMPANION_RESOURCES; +export const loadAll = (loader: LoaderPlugin): Promise => { + const promises: Promise[] = []; - resources.forEach((resource: CompanionResourceDescriptionInterface) => { - loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); + COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => { + promises.push(lazyLoadResource(loader, resource.name)); }); - return resources; + return Promise.all(promises).then(() => { + return COMPANION_RESOURCES; + }); } export const lazyLoadResource = (loader: LoaderPlugin, name: string): Promise => { diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index fbe5102c..70625b24 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -5,6 +5,7 @@ import {MenuScene, MenuSceneName} from "../Menu/MenuScene"; import {HelpCameraSettingsScene, HelpCameraSettingsSceneName} from "../Menu/HelpCameraSettingsScene"; import {LoginSceneName} from "../Login/LoginScene"; import {SelectCharacterSceneName} from "../Login/SelectCharacterScene"; +import {SelectCompanionSceneName} from "../Login/SelectCompanionScene"; import {EnableCameraSceneName} from "../Login/EnableCameraScene"; import {localUserStore} from "../../Connexion/LocalUserStore"; @@ -39,6 +40,8 @@ export class GameManager { return LoginSceneName; } else if (!this.characterLayers) { return SelectCharacterSceneName; + } else if (!localUserStore.wasCompanionSet()) { + return SelectCompanionSceneName; } else { return EnableCameraSceneName; } @@ -65,6 +68,11 @@ export class GameManager { return this.characterLayers; } + + setCompanion(companion: string|null): void { + this.companion = companion; + } + getCompanion(): string|null { return this.companion; } diff --git a/front/src/Phaser/Login/SelectCompanionScene.ts b/front/src/Phaser/Login/SelectCompanionScene.ts new file mode 100644 index 00000000..9b1cb09a --- /dev/null +++ b/front/src/Phaser/Login/SelectCompanionScene.ts @@ -0,0 +1,248 @@ +import Image = Phaser.GameObjects.Image; +import Rectangle = Phaser.GameObjects.Rectangle; +import {gameManager} from "../Game/GameManager"; +import { addLoader } from "../Components/Loader"; +import {TextField} from "../Components/TextField"; +import { ResizableScene } from "./ResizableScene"; +import {EnableCameraSceneName} from "./EnableCameraScene"; +import {localUserStore} from "../../Connexion/LocalUserStore"; +import { loadAll } from "../Companion/CompanionTexturesLoadingManager"; +import { CompanionResourceDescriptionInterface } from "../Companion/CompanionTextures"; + +export const SelectCompanionSceneName = "SelectCompanionScene"; + +enum LoginTextures { + playButton = "play_button", + icon = "icon", + mainFont = "main_font" +} + +export class SelectCompanionScene extends ResizableScene { + private logo!: Image; + private textField!: TextField; + private pressReturnField!: TextField; + private readonly nbCharactersPerRow = 7; + + private selectedRectangle!: Rectangle; + private selectedRectangleXPos = 0; + private selectedRectangleYPos = 0; + + private selectedCompanion!: Phaser.Physics.Arcade.Sprite; + private companions: Array = new Array(); + private companionModels: Array = [null]; + + constructor() { + super({ + key: SelectCompanionSceneName + }); + } + + preload() { + loadAll(this.load).then(resourceDescriptions => { + resourceDescriptions.forEach(resourceDescription => { + this.companionModels.push(resourceDescription); + }); + }); + + this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png"); + this.load.image(LoginTextures.playButton, "resources/objects/play_button.png"); + + // Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap + this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); + + addLoader(this); + } + + create() { + this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Select your companion'); + + this.pressReturnField = new TextField( + this, + this.game.renderer.width / 2, + 90 + 32 * Math.ceil(this.companionModels.length / this.nbCharactersPerRow), + 'Press enter to start' + ); + + const rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16; + this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xFFFFFF); + + this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon); + this.add.existing(this.logo); + + // input events + this.input.keyboard.on('keyup-ENTER', () => { + return this.nextScene(); + }); + + this.input.keyboard.on('keydown-RIGHT', () => { + if(this.selectedRectangleYPos * this.nbCharactersPerRow + (this.selectedRectangleXPos + 2)) + if ( + this.selectedRectangleXPos < this.nbCharactersPerRow - 1 + && ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos + 1) + 1) <= this.companionModels.length + ) { + this.selectedRectangleXPos++; + } + this.updateSelectedCompanion(); + }); + + this.input.keyboard.on('keydown-LEFT', () => { + if ( + this.selectedRectangleXPos > 0 + && ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos - 1) + 1) <= this.companionModels.length + ) { + this.selectedRectangleXPos--; + } + this.updateSelectedCompanion(); + }); + + this.input.keyboard.on('keydown-DOWN', () => { + if ( + this.selectedRectangleYPos + 1 < Math.ceil(this.companionModels.length / this.nbCharactersPerRow) + && ( + (((this.selectedRectangleYPos + 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.companionModels.length // check if companion isn't empty + || (this.selectedRectangleYPos + 1) === Math.ceil(this.companionModels.length / this.nbCharactersPerRow) // check if is custom rectangle + ) + ) { + this.selectedRectangleYPos++; + } + this.updateSelectedCompanion(); + }); + + this.input.keyboard.on('keydown-UP', () => { + if ( + this.selectedRectangleYPos > 0 + && (((this.selectedRectangleYPos - 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.companionModels.length + ) { + this.selectedRectangleYPos--; + } + this.updateSelectedCompanion(); + }); + + this.createCurrentCompanion(); + + const companionNumber = this.getCompanionIndex(); + + this.selectedRectangleXPos = companionNumber % this.nbCharactersPerRow; + this.selectedRectangleYPos = Math.floor(companionNumber / this.nbCharactersPerRow); + + this.updateSelectedCompanion(); + } + + update(time: number, delta: number): void { + this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2)); + } + + private nextScene(): void { + // store companion + const companionNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow; + const model = this.companionModels[companionNumber]; + const companion = model === null ? null : model.name; + + localUserStore.setCompanion(companion); + + // next scene + this.scene.stop(SelectCompanionSceneName); + + gameManager.setCompanion(companion); + gameManager.tryResumingGame(this, EnableCameraSceneName); + + this.scene.remove(SelectCompanionSceneName); + } + + private createCurrentCompanion(): void { + for (let i = 0; i < this.companionModels.length; i++) { + const companionResource = this.companionModels[i]; + + const col = i % this.nbCharactersPerRow; + const row = Math.floor(i / this.nbCharactersPerRow); + + const [x, y] = this.getCharacterPosition(col, row); + + let name = "null"; + if (companionResource !== null) { + name = companionResource.name; + } + + const companion = this.physics.add.sprite(x, y, name, 0); + companion.setBounce(0.2); + companion.setCollideWorldBounds(true); + + if (companionResource !== null) { + this.anims.create({ + key: name, + frames: this.anims.generateFrameNumbers(name, {start: 0, end: 2,}), + frameRate: 10, + repeat: -1 + }); + } + + companion.setInteractive().on("pointerdown", () => { + this.selectedRectangleXPos = col; + this.selectedRectangleYPos = row; + this.updateSelectedCompanion(); + }); + + this.companions.push(companion); + } + + this.selectedCompanion = this.companions[0]; + } + + private getCharacterPosition(x: number, y: number): [number, number] { + return [ + this.game.renderer.width / 2 + 16 + (x - this.nbCharactersPerRow / 2) * 32, + y * 32 + 90 + ]; + } + + private updateSelectedCompanion(): void { + this.selectedCompanion?.anims.pause(); + + const [x, y] = this.getCharacterPosition(this.selectedRectangleXPos, this.selectedRectangleYPos); + this.selectedRectangle.setVisible(true); + this.selectedRectangle.setX(x); + this.selectedRectangle.setY(y); + this.selectedRectangle.setSize(32, 32); + + const companionNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow; + const model = this.companionModels[companionNumber]; + + const companion = this.companions[companionNumber]; + + if (model !== null) { + companion.play(model.name); + } + + this.selectedCompanion = companion; + } + + public onResize(ev: UIEvent): void { + this.textField.x = this.game.renderer.width / 2; + this.pressReturnField.x = this.game.renderer.width / 2; + this.logo.x = this.game.renderer.width - 30; + this.logo.y = this.game.renderer.height - 20; + + for (let i = 0; i model !== null && model.name === companion); + } +} diff --git a/front/src/index.ts b/front/src/index.ts index c0663acd..aab45a9b 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -6,6 +6,7 @@ import {DEBUG_MODE, JITSI_URL, RESOLUTION} from "./Enum/EnvironmentVariable"; import {LoginScene} from "./Phaser/Login/LoginScene"; import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene"; import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene"; +import {SelectCompanionScene} from "./Phaser/Login/SelectCompanionScene"; import {EnableCameraScene} from "./Phaser/Login/EnableCameraScene"; import {CustomizeScene} from "./Phaser/Login/CustomizeScene"; import {ResizableScene} from "./Phaser/Login/ResizableScene"; @@ -74,7 +75,7 @@ const config: GameConfig = { width: width / RESOLUTION, height: height / RESOLUTION, parent: "game", - scene: [EntryScene, LoginScene, SelectCharacterScene, EnableCameraScene, ReconnectingScene, ErrorScene, CustomizeScene, MenuScene, HelpCameraSettingsScene], + scene: [EntryScene, LoginScene, SelectCharacterScene, SelectCompanionScene, EnableCameraScene, ReconnectingScene, ErrorScene, CustomizeScene, MenuScene, HelpCameraSettingsScene], zoom: RESOLUTION, fps: fps, dom: { From 6ee488977370e6abca60a05762ea98e8d0ae3947 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 23:13:03 +0200 Subject: [PATCH 09/20] added change companion button to menu --- front/dist/resources/html/gameMenu.html | 3 +++ .../CompanionTexturesLoadingManager.ts | 6 +++++- .../src/Phaser/Login/SelectCompanionScene.ts | 20 ++++++++++--------- front/src/Phaser/Menu/MenuScene.ts | 5 +++++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/front/dist/resources/html/gameMenu.html b/front/dist/resources/html/gameMenu.html index f0faf5c5..d5e9ad7e 100644 --- a/front/dist/resources/html/gameMenu.html +++ b/front/dist/resources/html/gameMenu.html @@ -30,6 +30,9 @@
+
+ +
diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index b7859a70..1c74b64f 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -1,7 +1,11 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin; import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures"; -export const loadAll = (loader: LoaderPlugin): Promise => { +export const getAllResources = (): CompanionResourceDescriptionInterface[] => { + return COMPANION_RESOURCES; +} + +export const lazyLoadAllResources = (loader: LoaderPlugin): Promise => { const promises: Promise[] = []; COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => { diff --git a/front/src/Phaser/Login/SelectCompanionScene.ts b/front/src/Phaser/Login/SelectCompanionScene.ts index 9b1cb09a..5a6cc160 100644 --- a/front/src/Phaser/Login/SelectCompanionScene.ts +++ b/front/src/Phaser/Login/SelectCompanionScene.ts @@ -1,13 +1,13 @@ import Image = Phaser.GameObjects.Image; import Rectangle = Phaser.GameObjects.Rectangle; -import {gameManager} from "../Game/GameManager"; import { addLoader } from "../Components/Loader"; -import {TextField} from "../Components/TextField"; +import { gameManager} from "../Game/GameManager"; import { ResizableScene } from "./ResizableScene"; -import {EnableCameraSceneName} from "./EnableCameraScene"; -import {localUserStore} from "../../Connexion/LocalUserStore"; -import { loadAll } from "../Companion/CompanionTexturesLoadingManager"; +import { TextField } from "../Components/TextField"; +import { EnableCameraSceneName } from "./EnableCameraScene"; +import { localUserStore } from "../../Connexion/LocalUserStore"; import { CompanionResourceDescriptionInterface } from "../Companion/CompanionTextures"; +import { getAllResources, lazyLoadAllResources } from "../Companion/CompanionTexturesLoadingManager"; export const SelectCompanionSceneName = "SelectCompanionScene"; @@ -38,10 +38,12 @@ export class SelectCompanionScene extends ResizableScene { } preload() { - loadAll(this.load).then(resourceDescriptions => { - resourceDescriptions.forEach(resourceDescription => { - this.companionModels.push(resourceDescription); - }); + lazyLoadAllResources(this.load).then(() => { + console.log("Loaded all companion textures."); + }); + + getAllResources().forEach(model => { + this.companionModels.push(model); }); this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png"); diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 58e7f0a6..f29fd39d 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -1,5 +1,6 @@ import {LoginScene, LoginSceneName} from "../Login/LoginScene"; import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene"; +import {SelectCompanionScene, SelectCompanionSceneName} from "../Login/SelectCompanionScene"; import {gameManager} from "../Game/GameManager"; import {localUserStore} from "../../Connexion/LocalUserStore"; import {mediaManager} from "../../WebRtc/MediaManager"; @@ -277,6 +278,10 @@ export class MenuScene extends Phaser.Scene { this.closeSideMenu(); gameManager.leaveGame(this, SelectCharacterSceneName, new SelectCharacterScene()); break; + case 'changeCompanionButton': + this.closeSideMenu(); + gameManager.leaveGame(this, SelectCompanionSceneName, new SelectCompanionScene()); + break; case 'closeButton': this.closeSideMenu(); break; From 38c06ce8ff634edb387f0e480ee0e3a9e39fc11b Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 23:17:04 +0200 Subject: [PATCH 10/20] navigate from select character scene to select companion scene --- front/src/Phaser/Login/SelectCharacterScene.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/front/src/Phaser/Login/SelectCharacterScene.ts b/front/src/Phaser/Login/SelectCharacterScene.ts index e47cf38a..1d595494 100644 --- a/front/src/Phaser/Login/SelectCharacterScene.ts +++ b/front/src/Phaser/Login/SelectCharacterScene.ts @@ -2,6 +2,7 @@ import {gameManager} from "../Game/GameManager"; import {TextField} from "../Components/TextField"; import Image = Phaser.GameObjects.Image; import Rectangle = Phaser.GameObjects.Rectangle; +import {SelectCompanionSceneName} from "./SelectCompanionScene"; import {EnableCameraSceneName} from "./EnableCameraScene"; import {CustomizeSceneName} from "./CustomizeScene"; import {ResizableScene} from "./ResizableScene"; @@ -145,7 +146,7 @@ export class SelectCharacterScene extends AbstractCharacterScene { this.scene.stop(SelectCharacterSceneName); if (this.selectedPlayer !== null) { gameManager.setCharacterLayers([this.selectedPlayer.texture.key]); - gameManager.tryResumingGame(this, EnableCameraSceneName); + gameManager.tryResumingGame(this, localUserStore.wasCompanionSet() ? EnableCameraSceneName : SelectCompanionSceneName); } else { this.scene.run(CustomizeSceneName); } From 3187520e7b4bc8c8b54098e6b6bc0496d0483b3f Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 23:36:06 +0200 Subject: [PATCH 11/20] companion behaviour fine tuning --- front/src/Phaser/Companion/Companion.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 2d11110e..cb932cbb 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -23,7 +23,7 @@ export class Companion extends Container { private animationType: PlayerAnimationTypes; constructor(scene: Phaser.Scene, x: number, y: number, name: string) { - super(scene, x + 8, y + 8); + super(scene, x + 14, y + 4); this.sprites = new Map(); @@ -59,7 +59,7 @@ export class Companion extends Container { } public setTarget(x: number, y: number, direction: PlayerAnimationDirections) { - this.target = { x, y, direction }; + this.target = { x, y: y + 4, direction }; } public step(time: number, delta: number) { @@ -76,7 +76,7 @@ export class Companion extends Container { const distance = Math.pow(xDist, 2) + Math.pow(yDist, 2); - if (distance < 576) { // 24^2 + if (distance < 650) { this.animationType = PlayerAnimationTypes.Idle; this.direction = this.target.direction; @@ -88,7 +88,7 @@ export class Companion extends Container { const yDir = yDist / Math.max(Math.abs(yDist), 1); const speed = 256; - this.getBody().setVelocity(Math.min(Math.abs(xDist * 2), speed) * xDir, Math.min(Math.abs(yDist * 2), speed) * yDir); + this.getBody().setVelocity(Math.min(Math.abs(xDist * 2.5), speed) * xDir, Math.min(Math.abs(yDist * 2.5), speed) * yDir); if (Math.abs(xDist) > Math.abs(yDist)) { if (xDist < 0) { From 8c35860f2abde025bcbe66ea2978f2f89d4147bd Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 2 Apr 2021 23:49:25 +0200 Subject: [PATCH 12/20] show select companion scene after customize scene --- front/src/Phaser/Login/CustomizeScene.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index 4f5b2860..87e5aac9 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -1,4 +1,5 @@ import {EnableCameraSceneName} from "./EnableCameraScene"; +import {SelectCompanionSceneName} from "./SelectCompanionScene"; import {TextField} from "../Components/TextField"; import Image = Phaser.GameObjects.Image; import Rectangle = Phaser.GameObjects.Rectangle; @@ -115,7 +116,7 @@ export class CustomizeScene extends AbstractCharacterScene { gameManager.setCharacterLayers(layers); this.scene.sleep(CustomizeSceneName); - gameManager.tryResumingGame(this, EnableCameraSceneName); + gameManager.tryResumingGame(this, localUserStore.wasCompanionSet() ? EnableCameraSceneName : SelectCompanionSceneName); }); this.input.keyboard.on('keyup-RIGHT', () => this.moveCursorHorizontally(1)); From 6c512fb7cd9d4b0f9391489b9e0919cba38ea88a Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Sat, 3 Apr 2021 00:18:08 +0200 Subject: [PATCH 13/20] fixed linting --- front/src/Phaser/Companion/Companion.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index cb932cbb..e578dd3d 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -16,6 +16,7 @@ export class Companion extends Container { private delta: number; private invisible: boolean; + private updateListener: Function; private target: { x: number, y: number, direction: PlayerAnimationDirections }; private companionName: string; @@ -53,7 +54,8 @@ export class Companion extends Container { this.setDepth(-1); - this.scene.events.addListener('update', this.step, this); + this.updateListener = this.step.bind(this); + this.scene.events.addListener('update', this.updateListener); this.scene.add.existing(this); } @@ -213,7 +215,7 @@ export class Companion extends Container { } if (this.scene) { - this.scene.events.removeListener('update', this.step, this); + this.scene.events.removeListener('update', this.updateListener); } super.destroy(); From 7c6b73efdbc8b7d178b93c4d26c1d8c900bf990a Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Tue, 6 Apr 2021 18:36:46 +0200 Subject: [PATCH 14/20] don't show companion selection during first connexion flow --- front/src/Phaser/Login/CustomizeScene.ts | 3 +-- front/src/Phaser/Login/SelectCharacterScene.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index 87e5aac9..4f5b2860 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -1,5 +1,4 @@ import {EnableCameraSceneName} from "./EnableCameraScene"; -import {SelectCompanionSceneName} from "./SelectCompanionScene"; import {TextField} from "../Components/TextField"; import Image = Phaser.GameObjects.Image; import Rectangle = Phaser.GameObjects.Rectangle; @@ -116,7 +115,7 @@ export class CustomizeScene extends AbstractCharacterScene { gameManager.setCharacterLayers(layers); this.scene.sleep(CustomizeSceneName); - gameManager.tryResumingGame(this, localUserStore.wasCompanionSet() ? EnableCameraSceneName : SelectCompanionSceneName); + gameManager.tryResumingGame(this, EnableCameraSceneName); }); this.input.keyboard.on('keyup-RIGHT', () => this.moveCursorHorizontally(1)); diff --git a/front/src/Phaser/Login/SelectCharacterScene.ts b/front/src/Phaser/Login/SelectCharacterScene.ts index 1d595494..e47cf38a 100644 --- a/front/src/Phaser/Login/SelectCharacterScene.ts +++ b/front/src/Phaser/Login/SelectCharacterScene.ts @@ -2,7 +2,6 @@ import {gameManager} from "../Game/GameManager"; import {TextField} from "../Components/TextField"; import Image = Phaser.GameObjects.Image; import Rectangle = Phaser.GameObjects.Rectangle; -import {SelectCompanionSceneName} from "./SelectCompanionScene"; import {EnableCameraSceneName} from "./EnableCameraScene"; import {CustomizeSceneName} from "./CustomizeScene"; import {ResizableScene} from "./ResizableScene"; @@ -146,7 +145,7 @@ export class SelectCharacterScene extends AbstractCharacterScene { this.scene.stop(SelectCharacterSceneName); if (this.selectedPlayer !== null) { gameManager.setCharacterLayers([this.selectedPlayer.texture.key]); - gameManager.tryResumingGame(this, localUserStore.wasCompanionSet() ? EnableCameraSceneName : SelectCompanionSceneName); + gameManager.tryResumingGame(this, EnableCameraSceneName); } else { this.scene.run(CustomizeSceneName); } From e5a196a42bdbe0b601c139ddef9cde9cec6fc78c Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Tue, 6 Apr 2021 18:54:45 +0200 Subject: [PATCH 15/20] implemented feedback --- back/src/Model/User.ts | 4 ++-- front/src/Connexion/LocalUserStore.ts | 8 +++++++- front/src/Phaser/Companion/Companion.ts | 4 ++-- .../CompanionTexturesLoadingManager.ts | 20 ++++++------------- .../src/Phaser/Login/SelectCompanionScene.ts | 8 +++----- messages/protos/messages.proto | 8 ++++---- pusher/src/Controller/IoSocketController.ts | 6 +++--- .../src/Model/Websocket/ExSocketInterface.ts | 4 ++-- pusher/src/Model/Zone.ts | 4 ++-- 9 files changed, 31 insertions(+), 35 deletions(-) diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index 370781e5..52a96b61 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -4,7 +4,7 @@ import {Zone} from "_Model/Zone"; import {Movable} from "_Model/Movable"; import {PositionNotifier} from "_Model/PositionNotifier"; import {ServerDuplexStream} from "grpc"; -import {BatchMessage, Companion, PusherToBackMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb"; +import {BatchMessage, CompanionMessage, PusherToBackMessage, ServerToClientMessage, SubMessage} from "../Messages/generated/messages_pb"; import {CharacterLayer} from "_Model/Websocket/CharacterLayer"; export type UserSocket = ServerDuplexStream; @@ -24,7 +24,7 @@ export class User implements Movable { public readonly tags: string[], public readonly name: string, public readonly characterLayers: CharacterLayer[], - public readonly companion?: Companion + public readonly companion?: CompanionMessage ) { this.listenedZones = new Set(); diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index a766f5dc..74e45049 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -52,7 +52,13 @@ class LocalUserStore { return localStorage.setItem(companionKey, JSON.stringify(companion)); } getCompanion(): string|null { - return JSON.parse(localStorage.getItem(companionKey) || "null"); + const companion = JSON.parse(localStorage.getItem(companionKey) || "null"); + + if (typeof companion !== "string" || companion === "") { + return null; + } + + return companion; } wasCompanionSet(): boolean { return localStorage.getItem(companionKey) ? true : false; diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index e578dd3d..48a3fa4b 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -1,6 +1,6 @@ import Sprite = Phaser.GameObjects.Sprite; import Container = Phaser.GameObjects.Container; -import { lazyLoadResource } from "./CompanionTexturesLoadingManager"; +import { lazyLoadCompanionResource } from "./CompanionTexturesLoadingManager"; import { PlayerAnimationDirections, PlayerAnimationTypes } from "../Player/Animation"; export interface CompanionStatus { @@ -37,7 +37,7 @@ export class Companion extends Container { this.companionName = name; - lazyLoadResource(this.scene.load, this.companionName) + lazyLoadCompanionResource(this.scene.load, this.companionName) .then(resource => { this.addResource(resource); this.invisible = false; diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index 1c74b64f..354c5740 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -1,23 +1,15 @@ import LoaderPlugin = Phaser.Loader.LoaderPlugin; import { COMPANION_RESOURCES, CompanionResourceDescriptionInterface } from "./CompanionTextures"; -export const getAllResources = (): CompanionResourceDescriptionInterface[] => { +export const getAllCompanionResources = (loader: LoaderPlugin): CompanionResourceDescriptionInterface[] => { + COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => { + lazyLoadCompanionResource(loader, resource.name); + }); + return COMPANION_RESOURCES; } -export const lazyLoadAllResources = (loader: LoaderPlugin): Promise => { - const promises: Promise[] = []; - - COMPANION_RESOURCES.forEach((resource: CompanionResourceDescriptionInterface) => { - promises.push(lazyLoadResource(loader, resource.name)); - }); - - return Promise.all(promises).then(() => { - return COMPANION_RESOURCES; - }); -} - -export const lazyLoadResource = (loader: LoaderPlugin, name: string): Promise => { +export const lazyLoadCompanionResource = (loader: LoaderPlugin, name: string): Promise => { return new Promise((resolve, reject) => { const resource = COMPANION_RESOURCES.find(item => item.name === name); diff --git a/front/src/Phaser/Login/SelectCompanionScene.ts b/front/src/Phaser/Login/SelectCompanionScene.ts index 5a6cc160..3d20d35a 100644 --- a/front/src/Phaser/Login/SelectCompanionScene.ts +++ b/front/src/Phaser/Login/SelectCompanionScene.ts @@ -7,7 +7,7 @@ import { TextField } from "../Components/TextField"; import { EnableCameraSceneName } from "./EnableCameraScene"; import { localUserStore } from "../../Connexion/LocalUserStore"; import { CompanionResourceDescriptionInterface } from "../Companion/CompanionTextures"; -import { getAllResources, lazyLoadAllResources } from "../Companion/CompanionTexturesLoadingManager"; +import { getAllCompanionResources } from "../Companion/CompanionTexturesLoadingManager"; export const SelectCompanionSceneName = "SelectCompanionScene"; @@ -38,11 +38,9 @@ export class SelectCompanionScene extends ResizableScene { } preload() { - lazyLoadAllResources(this.load).then(() => { - console.log("Loaded all companion textures."); - }); + addLoader(this); - getAllResources().forEach(model => { + getAllCompanionResources(this.load).forEach(model => { this.companionModels.push(model); }); diff --git a/messages/protos/messages.proto b/messages/protos/messages.proto index 372f00b7..b3d4e755 100644 --- a/messages/protos/messages.proto +++ b/messages/protos/messages.proto @@ -36,7 +36,7 @@ message CharacterLayerMessage { string name = 2; } -message Companion { +message CompanionMessage { string name = 1; } @@ -145,7 +145,7 @@ message UserJoinedMessage { string name = 2; repeated CharacterLayerMessage characterLayers = 3; PositionMessage position = 4; - Companion companion = 5; + CompanionMessage companion = 5; } message UserLeftMessage { @@ -256,7 +256,7 @@ message JoinRoomMessage { string roomId = 5; repeated string tag = 6; string IPAddress = 7; - Companion companion = 8; + CompanionMessage companion = 8; } message UserJoinedZoneMessage { @@ -265,7 +265,7 @@ message UserJoinedZoneMessage { repeated CharacterLayerMessage characterLayers = 3; PositionMessage position = 4; Zone fromZone = 5; - Companion companion = 6; + CompanionMessage companion = 6; } message UserLeftZoneMessage { diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 2079548f..87051bbc 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -12,7 +12,7 @@ import { WebRtcSignalToServerMessage, PlayGlobalMessage, ReportPlayerMessage, - QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage, Companion + QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage, CompanionMessage } from "../Messages/generated/messages_pb"; import {UserMovesMessage} from "../Messages/generated/messages_pb"; import {TemplatedApp} from "uWebSockets.js" @@ -139,10 +139,10 @@ export class IoSocketController { const right = Number(query.right); const name = query.name; - let companion: Companion|undefined = undefined; + let companion: CompanionMessage|undefined = undefined; if (typeof query.companion === 'string') { - companion = new Companion(); + companion = new CompanionMessage(); companion.setName(query.companion); } diff --git a/pusher/src/Model/Websocket/ExSocketInterface.ts b/pusher/src/Model/Websocket/ExSocketInterface.ts index 135c6f10..5b9a4f7e 100644 --- a/pusher/src/Model/Websocket/ExSocketInterface.ts +++ b/pusher/src/Model/Websocket/ExSocketInterface.ts @@ -3,7 +3,7 @@ import {Identificable} from "./Identificable"; import {ViewportInterface} from "_Model/Websocket/ViewportMessage"; import { BatchMessage, - Companion, + CompanionMessage, PusherToBackMessage, ServerToClientMessage, SubMessage @@ -30,7 +30,7 @@ export interface ExSocketInterface extends WebSocket, Identificable { characterLayers: CharacterLayer[]; position: PointInterface; viewport: ViewportInterface; - companion?: Companion; + companion?: CompanionMessage; /** * Pushes an event that will be sent in the next batch of events */ diff --git a/pusher/src/Model/Zone.ts b/pusher/src/Model/Zone.ts index a54481a5..3f39a5ed 100644 --- a/pusher/src/Model/Zone.ts +++ b/pusher/src/Model/Zone.ts @@ -6,7 +6,7 @@ import { PointMessage, PositionMessage, UserJoinedMessage, UserJoinedZoneMessage, UserLeftZoneMessage, UserMovedMessage, ZoneMessage, - Companion + CompanionMessage } from "../Messages/generated/messages_pb"; import * as messages_pb from "../Messages/generated/messages_pb"; import {ClientReadableStream} from "grpc"; @@ -31,7 +31,7 @@ export type MovesCallback = (thing: Movable, position: PositionInterface, listen export type LeavesCallback = (thing: Movable, listener: User) => void;*/ export class UserDescriptor { - private constructor(public readonly userId: number, private name: string, private characterLayers: CharacterLayerMessage[], private position: PositionMessage, private companion?: Companion) { + private constructor(public readonly userId: number, private name: string, private characterLayers: CharacterLayerMessage[], private position: PositionMessage, private companion?: CompanionMessage) { if (!Number.isInteger(this.userId)) { throw new Error('UserDescriptor.userId is not an integer: '+this.userId); } From 187e21eed98c3b017eb366aa019920203c3207f0 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Tue, 6 Apr 2021 19:10:18 +0200 Subject: [PATCH 16/20] load texture inside game scene instead inside of inside companion class --- front/src/Phaser/Companion/Companion.ts | 12 +++++------- front/src/Phaser/Entity/Character.ts | 6 ++++-- front/src/Phaser/Entity/RemotePlayer.ts | 5 +++-- front/src/Phaser/Game/GameScene.ts | 7 +++++-- front/src/Phaser/Player/Player.ts | 5 +++-- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/front/src/Phaser/Companion/Companion.ts b/front/src/Phaser/Companion/Companion.ts index 48a3fa4b..72491ae1 100644 --- a/front/src/Phaser/Companion/Companion.ts +++ b/front/src/Phaser/Companion/Companion.ts @@ -23,7 +23,7 @@ export class Companion extends Container { private direction: PlayerAnimationDirections; private animationType: PlayerAnimationTypes; - constructor(scene: Phaser.Scene, x: number, y: number, name: string) { + constructor(scene: Phaser.Scene, x: number, y: number, name: string, texturePromise: Promise) { super(scene, x + 14, y + 4); this.sprites = new Map(); @@ -37,12 +37,10 @@ export class Companion extends Container { this.companionName = name; - lazyLoadCompanionResource(this.scene.load, this.companionName) - .then(resource => { - this.addResource(resource); - this.invisible = false; - }) - .catch(error => console.error(error)); + texturePromise.then(resource => { + this.addResource(resource); + this.invisible = false; + }) this.scene.physics.world.enableBody(this); diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index eb8e45fd..5b541267 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -71,8 +71,10 @@ export abstract class Character extends Container { this.playAnimation(direction, moving); } - public addCompanion(name: string): void { - this.companion = new Companion(this.scene, this.x, this.y, name); + public addCompanion(name: string, texturePromise?: Promise): void { + if (typeof texturePromise !== 'undefined') { + this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise); + } } public addTextures(textures: string[], frame?: string | number): void { diff --git a/front/src/Phaser/Entity/RemotePlayer.ts b/front/src/Phaser/Entity/RemotePlayer.ts index b405d8df..41e2e2df 100644 --- a/front/src/Phaser/Entity/RemotePlayer.ts +++ b/front/src/Phaser/Entity/RemotePlayer.ts @@ -18,7 +18,8 @@ export class RemotePlayer extends Character { texturesPromise: Promise, direction: PlayerAnimationDirections, moving: boolean, - companion: string|null + companion: string|null, + companionTexturePromise?: Promise ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1); @@ -26,7 +27,7 @@ export class RemotePlayer extends Character { this.userId = userId; if (typeof companion === 'string') { - this.addCompanion(companion); + this.addCompanion(companion, companionTexturePromise); } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 222f7ed5..7cbefb39 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -69,6 +69,7 @@ import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import DOMElement = Phaser.GameObjects.DOMElement; import {Subscription} from "rxjs"; import {worldFullMessageStream} from "../../Connexion/WorldFullMessageStream"; +import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; export interface GameSceneInitInterface { initPosition: PointInterface|null, @@ -1024,7 +1025,8 @@ ${escapedMessage} PlayerAnimationDirections.Down, false, this.userInputManager, - this.companion + this.companion, + this.companion !== null ? lazyLoadCompanionResource(this.load, this.companion) : undefined ); }catch (err){ if(err instanceof TextureError) { @@ -1217,7 +1219,8 @@ ${escapedMessage} texturesPromise, addPlayerData.position.direction as PlayerAnimationDirections, addPlayerData.position.moving, - addPlayerData.companion + addPlayerData.companion, + addPlayerData.companion !== null ? lazyLoadCompanionResource(this.load, addPlayerData.companion) : undefined ); this.MapPlayers.add(player); this.MapPlayersByKey.set(player.userId, player); diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index d018a41f..bb961115 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -22,7 +22,8 @@ export class Player extends Character implements CurrentGamerInterface { direction: PlayerAnimationDirections, moving: boolean, private userInputManager: UserInputManager, - companion: string|null + companion: string|null, + companionTexturePromise?: Promise ) { super(Scene, x, y, texturesPromise, name, direction, moving, 1); @@ -30,7 +31,7 @@ export class Player extends Character implements CurrentGamerInterface { this.getBody().setImmovable(false); if (typeof companion === 'string') { - this.addCompanion(companion); + this.addCompanion(companion, companionTexturePromise); } } From fb90111cdf30c77740f0d027a34dc9558af76e55 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Tue, 6 Apr 2021 20:12:10 +0200 Subject: [PATCH 17/20] refactored companion selection scene --- .../src/Phaser/Login/SelectCompanionScene.ts | 154 ++++++++---------- 1 file changed, 69 insertions(+), 85 deletions(-) diff --git a/front/src/Phaser/Login/SelectCompanionScene.ts b/front/src/Phaser/Login/SelectCompanionScene.ts index 3d20d35a..34892a3c 100644 --- a/front/src/Phaser/Login/SelectCompanionScene.ts +++ b/front/src/Phaser/Login/SelectCompanionScene.ts @@ -24,8 +24,6 @@ export class SelectCompanionScene extends ResizableScene { private readonly nbCharactersPerRow = 7; private selectedRectangle!: Rectangle; - private selectedRectangleXPos = 0; - private selectedRectangleYPos = 0; private selectedCompanion!: Phaser.Physics.Arcade.Sprite; private companions: Array = new Array(); @@ -70,76 +68,85 @@ export class SelectCompanionScene extends ResizableScene { this.add.existing(this.logo); // input events - this.input.keyboard.on('keyup-ENTER', () => { - return this.nextScene(); - }); + this.input.keyboard.on('keyup-ENTER', this.nextScene.bind(this)); - this.input.keyboard.on('keydown-RIGHT', () => { - if(this.selectedRectangleYPos * this.nbCharactersPerRow + (this.selectedRectangleXPos + 2)) - if ( - this.selectedRectangleXPos < this.nbCharactersPerRow - 1 - && ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos + 1) + 1) <= this.companionModels.length - ) { - this.selectedRectangleXPos++; - } - this.updateSelectedCompanion(); - }); - - this.input.keyboard.on('keydown-LEFT', () => { - if ( - this.selectedRectangleXPos > 0 - && ((this.selectedRectangleYPos * this.nbCharactersPerRow) + (this.selectedRectangleXPos - 1) + 1) <= this.companionModels.length - ) { - this.selectedRectangleXPos--; - } - this.updateSelectedCompanion(); - }); - - this.input.keyboard.on('keydown-DOWN', () => { - if ( - this.selectedRectangleYPos + 1 < Math.ceil(this.companionModels.length / this.nbCharactersPerRow) - && ( - (((this.selectedRectangleYPos + 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.companionModels.length // check if companion isn't empty - || (this.selectedRectangleYPos + 1) === Math.ceil(this.companionModels.length / this.nbCharactersPerRow) // check if is custom rectangle - ) - ) { - this.selectedRectangleYPos++; - } - this.updateSelectedCompanion(); - }); - - this.input.keyboard.on('keydown-UP', () => { - if ( - this.selectedRectangleYPos > 0 - && (((this.selectedRectangleYPos - 1) * this.nbCharactersPerRow) + this.selectedRectangleXPos + 1) <= this.companionModels.length - ) { - this.selectedRectangleYPos--; - } - this.updateSelectedCompanion(); - }); + this.input.keyboard.on('keydown-RIGHT', this.selectNext.bind(this)); + this.input.keyboard.on('keydown-LEFT', this.selectPrevious.bind(this)); + this.input.keyboard.on('keydown-DOWN', this.jumpToNextRow.bind(this)); + this.input.keyboard.on('keydown-UP', this.jumpToPreviousRow.bind(this)); this.createCurrentCompanion(); - - const companionNumber = this.getCompanionIndex(); - - this.selectedRectangleXPos = companionNumber % this.nbCharactersPerRow; - this.selectedRectangleYPos = Math.floor(companionNumber / this.nbCharactersPerRow); - - this.updateSelectedCompanion(); + this.selectCompanion(this.getCompanionIndex()); } update(time: number, delta: number): void { this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2)); } - private nextScene(): void { - // store companion - const companionNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow; - const model = this.companionModels[companionNumber]; + private jumpToPreviousRow(): void { + const index = this.companions.indexOf(this.selectedCompanion) - this.nbCharactersPerRow; + if (index >= 0) { + this.selectCompanion(index); + } + } + + private jumpToNextRow(): void { + const index = this.companions.indexOf(this.selectedCompanion) + this.nbCharactersPerRow; + if (index < this.companions.length) { + this.selectCompanion(index); + } + } + + private selectPrevious(): void { + const index = this.companions.indexOf(this.selectedCompanion); + this.selectCompanion(index - 1); + } + + private selectNext(): void { + const index = this.companions.indexOf(this.selectedCompanion); + this.selectCompanion(index + 1); + } + + private selectCompanion(index?: number): void { + if (typeof index === 'undefined') { + index = this.companions.indexOf(this.selectedCompanion); + } + + // make sure index is inside possible range + index = Math.min(this.companions.length - 1, Math.max(0, index)); + + if (this.selectedCompanion === this.companions[index]) { + return; + } + + this.selectedCompanion.anims.pause(); + this.selectedCompanion = this.companions[index]; + + this.selectedRectangle.setVisible(true); + this.selectedRectangle.setX(this.selectedCompanion.x); + this.selectedRectangle.setY(this.selectedCompanion.y); + this.selectedRectangle.setSize(32, 32); + + const model = this.companionModels[index]; + + if (model !== null) { + this.selectedCompanion.anims.play(model.name); + } + } + + private storeCompanionSelection(): string|null { + const index = this.companions.indexOf(this.selectedCompanion); + const model = this.companionModels[index]; const companion = model === null ? null : model.name; localUserStore.setCompanion(companion); + return companion; + } + + private nextScene(): void { + const companion = this.storeCompanionSelection(); + // next scene this.scene.stop(SelectCompanionSceneName); @@ -177,9 +184,7 @@ export class SelectCompanionScene extends ResizableScene { } companion.setInteractive().on("pointerdown", () => { - this.selectedRectangleXPos = col; - this.selectedRectangleYPos = row; - this.updateSelectedCompanion(); + this.selectCompanion(i); }); this.companions.push(companion); @@ -195,34 +200,13 @@ export class SelectCompanionScene extends ResizableScene { ]; } - private updateSelectedCompanion(): void { - this.selectedCompanion?.anims.pause(); - - const [x, y] = this.getCharacterPosition(this.selectedRectangleXPos, this.selectedRectangleYPos); - this.selectedRectangle.setVisible(true); - this.selectedRectangle.setX(x); - this.selectedRectangle.setY(y); - this.selectedRectangle.setSize(32, 32); - - const companionNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow; - const model = this.companionModels[companionNumber]; - - const companion = this.companions[companionNumber]; - - if (model !== null) { - companion.play(model.name); - } - - this.selectedCompanion = companion; - } - public onResize(ev: UIEvent): void { this.textField.x = this.game.renderer.width / 2; this.pressReturnField.x = this.game.renderer.width / 2; this.logo.x = this.game.renderer.width - 30; this.logo.y = this.game.renderer.height - 20; - for (let i = 0; i Date: Tue, 6 Apr 2021 20:31:08 +0200 Subject: [PATCH 18/20] fixed rectangle resize issue --- front/src/Phaser/Login/SelectCompanionScene.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/front/src/Phaser/Login/SelectCompanionScene.ts b/front/src/Phaser/Login/SelectCompanionScene.ts index 34892a3c..9b5c38fb 100644 --- a/front/src/Phaser/Login/SelectCompanionScene.ts +++ b/front/src/Phaser/Login/SelectCompanionScene.ts @@ -122,10 +122,7 @@ export class SelectCompanionScene extends ResizableScene { this.selectedCompanion.anims.pause(); this.selectedCompanion = this.companions[index]; - this.selectedRectangle.setVisible(true); - this.selectedRectangle.setX(this.selectedCompanion.x); - this.selectedRectangle.setY(this.selectedCompanion.y); - this.selectedRectangle.setSize(32, 32); + this.redrawSelectedRectangle(); const model = this.companionModels[index]; @@ -134,6 +131,13 @@ export class SelectCompanionScene extends ResizableScene { } } + private redrawSelectedRectangle(): void { + this.selectedRectangle.setVisible(true); + this.selectedRectangle.setX(this.selectedCompanion.x); + this.selectedRectangle.setY(this.selectedCompanion.y); + this.selectedRectangle.setSize(32, 32); + } + private storeCompanionSelection(): string|null { const index = this.companions.indexOf(this.selectedCompanion); const model = this.companionModels[index]; @@ -217,7 +221,7 @@ export class SelectCompanionScene extends ResizableScene { companion.y = y; } - this.selectCompanion(); + this.redrawSelectedRectangle(); } private getCompanionIndex(): number { From 73e515c2368fcb6667a8f94b12d93231a377b646 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Thu, 8 Apr 2021 18:42:05 +0200 Subject: [PATCH 19/20] don't show companion scene after first refresh --- front/src/Phaser/Game/GameManager.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 70625b24..41d827a3 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -5,7 +5,6 @@ import {MenuScene, MenuSceneName} from "../Menu/MenuScene"; import {HelpCameraSettingsScene, HelpCameraSettingsSceneName} from "../Menu/HelpCameraSettingsScene"; import {LoginSceneName} from "../Login/LoginScene"; import {SelectCharacterSceneName} from "../Login/SelectCharacterScene"; -import {SelectCompanionSceneName} from "../Login/SelectCompanionScene"; import {EnableCameraSceneName} from "../Login/EnableCameraScene"; import {localUserStore} from "../../Connexion/LocalUserStore"; @@ -40,8 +39,6 @@ export class GameManager { return LoginSceneName; } else if (!this.characterLayers) { return SelectCharacterSceneName; - } else if (!localUserStore.wasCompanionSet()) { - return SelectCompanionSceneName; } else { return EnableCameraSceneName; } From 8d4e0c3e88db92c142c2f424b93a46fe3a02a463 Mon Sep 17 00:00:00 2001 From: Johannes Berthel Date: Fri, 9 Apr 2021 18:30:30 +0200 Subject: [PATCH 20/20] added companion compatibility with phaser 3.54.0 --- .../Companion/CompanionTexturesLoadingManager.ts | 2 ++ front/src/Phaser/Entity/Character.ts | 4 ---- front/src/Phaser/Game/GameScene.ts | 10 ++++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts index 354c5740..75c20a48 100644 --- a/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts +++ b/front/src/Phaser/Companion/CompanionTexturesLoadingManager.ts @@ -23,5 +23,7 @@ export const lazyLoadCompanionResource = (loader: LoaderPlugin, name: string): P loader.spritesheet(resource.name, resource.img, { frameWidth: 32, frameHeight: 32, endFrame: 12 }); loader.once(`filecomplete-spritesheet-${resource.name}`, () => resolve(resource.name)); + + loader.start(); // It's only automatically started during the Scene preload. }); } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 5b541267..9f2bd1fd 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -227,9 +227,5 @@ export abstract class Character extends Container { } super.destroy(); this.playerName.destroy(); - - if (this.companion) { - this.companion.destroy(); - } } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7cbefb39..5feb0607 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -854,6 +854,11 @@ ${escapedMessage} private removeAllRemotePlayers(): void { this.MapPlayersByKey.forEach((player: RemotePlayer) => { player.destroy(); + + if (player.companion) { + player.companion.destroy(); + } + this.MapPlayers.remove(player); }); this.MapPlayersByKey = new Map(); @@ -1243,6 +1248,11 @@ ${escapedMessage} console.error('Cannot find user with id ', userId); } else { player.destroy(); + + if (player.companion) { + player.companion.destroy(); + } + this.MapPlayers.remove(player); } this.MapPlayersByKey.delete(userId);