From 84529d6e995a00a0c73d99b657dcabeb165257e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 28 Jul 2020 17:43:33 +0200 Subject: [PATCH] Propagating customized sprites all over the game --- back/src/Controller/IoSocketController.ts | 6 +- back/src/Model/Websocket/ExSocketInterface.ts | 2 +- back/src/Model/Websocket/MessageUserJoined.ts | 2 +- .../Model/Websocket/MessageUserPosition.ts | 2 +- .../Websocket/SetPlayerDetailsMessage.ts | 2 +- front/src/Connection.ts | 10 +- front/src/Messages/SetPlayerDetailsMessage.ts | 2 +- front/src/Phaser/Entity/Character.ts | 124 +++++++++++------- front/src/Phaser/Entity/RemotePlayer.ts | 4 +- front/src/Phaser/Game/AddPlayerInterface.ts | 2 +- front/src/Phaser/Game/GameManager.ts | 4 +- front/src/Phaser/Game/GameScene.ts | 4 +- front/src/Phaser/Login/CustomizeScene.ts | 2 +- front/src/Phaser/Player/Player.ts | 6 +- 14 files changed, 99 insertions(+), 73 deletions(-) diff --git a/back/src/Controller/IoSocketController.ts b/back/src/Controller/IoSocketController.ts index edd29e7b..28dd2da2 100644 --- a/back/src/Controller/IoSocketController.ts +++ b/back/src/Controller/IoSocketController.ts @@ -177,7 +177,7 @@ export class IoSocketController { //add function to refresh position user in real time. //this.refreshUserPosition(Client); - const messageUserJoined = new MessageUserJoined(Client.userId, Client.name, Client.character, Client.position); + const messageUserJoined = new MessageUserJoined(Client.userId, Client.name, Client.characterLayers, Client.position); socket.to(roomId).emit(SockerIoEvent.JOIN_ROOM, messageUserJoined); @@ -188,7 +188,7 @@ export class IoSocketController { console.warn('Something went wrong. The World contains a user "'+user.id+"' but this user does not exist in the sockets list!"); return null; } - return new MessageUserPosition(user.id, player.name, player.character, player.position); + return new MessageUserPosition(user.id, player.name, player.characterLayers, player.position); }).filter((item: MessageUserPosition|null) => item !== null); answerFn(listOfUsers); } catch (e) { @@ -278,7 +278,7 @@ export class IoSocketController { } const Client = (socket as ExSocketInterface); Client.name = playerDetails.name; - Client.character = playerDetails.character; + Client.characterLayers = playerDetails.characterLayers; answerFn(Client.userId); }); }); diff --git a/back/src/Model/Websocket/ExSocketInterface.ts b/back/src/Model/Websocket/ExSocketInterface.ts index 5827ccc9..108c61cb 100644 --- a/back/src/Model/Websocket/ExSocketInterface.ts +++ b/back/src/Model/Websocket/ExSocketInterface.ts @@ -9,6 +9,6 @@ export interface ExSocketInterface extends Socket, Identificable { webRtcRoomId: string; userId: string; name: string; - character: string; + characterLayers: string[]; position: PointInterface; } diff --git a/back/src/Model/Websocket/MessageUserJoined.ts b/back/src/Model/Websocket/MessageUserJoined.ts index d3143a6b..9e993dd3 100644 --- a/back/src/Model/Websocket/MessageUserJoined.ts +++ b/back/src/Model/Websocket/MessageUserJoined.ts @@ -1,6 +1,6 @@ import {PointInterface} from "_Model/Websocket/PointInterface"; export class MessageUserJoined { - constructor(public userId: string, public name: string, public character: string, public position: PointInterface) { + constructor(public userId: string, public name: string, public characterLayers: string[], public position: PointInterface) { } } diff --git a/back/src/Model/Websocket/MessageUserPosition.ts b/back/src/Model/Websocket/MessageUserPosition.ts index ed604940..03fc6f09 100644 --- a/back/src/Model/Websocket/MessageUserPosition.ts +++ b/back/src/Model/Websocket/MessageUserPosition.ts @@ -6,6 +6,6 @@ export class Point implements PointInterface{ } export class MessageUserPosition { - constructor(public userId: string, public name: string, public character: string, public position: PointInterface) { + constructor(public userId: string, public name: string, public characterLayers: string[], public position: PointInterface) { } } diff --git a/back/src/Model/Websocket/SetPlayerDetailsMessage.ts b/back/src/Model/Websocket/SetPlayerDetailsMessage.ts index 21461812..1693f9a0 100644 --- a/back/src/Model/Websocket/SetPlayerDetailsMessage.ts +++ b/back/src/Model/Websocket/SetPlayerDetailsMessage.ts @@ -3,6 +3,6 @@ import * as tg from "generic-type-guard"; export const isSetPlayerDetailsMessage = new tg.IsInterface().withProperties({ name: tg.isString, - character: tg.isString + characterLayers: tg.isArray(tg.isString) }).get(); export type SetPlayerDetailsMessage = tg.GuardedType; diff --git a/front/src/Connection.ts b/front/src/Connection.ts index c4ac92c6..04715df6 100644 --- a/front/src/Connection.ts +++ b/front/src/Connection.ts @@ -44,7 +44,7 @@ export class Point implements PointInterface{ export interface MessageUserPositionInterface { userId: string; name: string; - character: string; + characterLayers: string[]; position: PointInterface; } @@ -56,7 +56,7 @@ export interface MessageUserMovedInterface { export interface MessageUserJoined { userId: string; name: string; - character: string; + characterLayers: string[]; position: PointInterface } @@ -109,7 +109,7 @@ export class Connection implements Connection { }) } - public static createConnection(name: string, characterSelected: string): Promise { + public static createConnection(name: string, characterLayersSelected: string[]): Promise { return Axios.post(`${API_URL}/login`, {name: name}) .then((res) => { @@ -123,7 +123,7 @@ export class Connection implements Connection { connection.socket.emit(EventMessage.SET_PLAYER_DETAILS, { name: name, - character: characterSelected + characterLayers: characterLayersSelected } as SetPlayerDetailsMessage, (id: string) => { connection.userId = id; }); @@ -135,7 +135,7 @@ export class Connection implements Connection { // Let's retry in 4-6 seconds return new Promise((resolve, reject) => { setTimeout(() => { - Connection.createConnection(name, characterSelected).then((connection) => resolve(connection)) + Connection.createConnection(name, characterLayersSelected).then((connection) => resolve(connection)) .catch((error) => reject(error)); }, 4000 + Math.floor(Math.random() * 2000) ); }); diff --git a/front/src/Messages/SetPlayerDetailsMessage.ts b/front/src/Messages/SetPlayerDetailsMessage.ts index 2f3cc707..789833ff 100644 --- a/front/src/Messages/SetPlayerDetailsMessage.ts +++ b/front/src/Messages/SetPlayerDetailsMessage.ts @@ -1,4 +1,4 @@ export interface SetPlayerDetailsMessage { name: string, - character: string + characterLayers: string[] } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 7453dc75..c3c4def4 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -1,6 +1,8 @@ import {PlayerAnimationNames} from "../Player/Animation"; import {SpeechBubble} from "./SpeechBubble"; import BitmapText = Phaser.GameObjects.BitmapText; +import Container = Phaser.GameObjects.Container; +import Sprite = Phaser.GameObjects.Sprite; export interface PlayerResourceDescriptionInterface { name: string, @@ -38,57 +40,62 @@ interface AnimationData { frameEnd: number; } -export abstract class Character extends Phaser.Physics.Arcade.Sprite { +export abstract class Character extends Container { private bubble: SpeechBubble|null = null; private readonly playerName: BitmapText; public PlayerValue: string; - public PlayerTexture: string; - + public sprites: Map; + private lastDirection: string = PlayerAnimationNames.WalkDown; constructor(scene: Phaser.Scene, x: number, y: number, - texture: string, + textures: string[], name: string, direction: string, moving: boolean, frame?: string | number ) { - super(scene, x, y, texture, frame); + super(scene, x, y/*, texture, frame*/); + + this.sprites = new Map(); + + for (const texture of textures) { + const sprite = new Sprite(scene, 0, 0, texture, frame); + this.getPlayerAnimations(texture).forEach(d => { + this.scene.anims.create({ + key: d.key, + frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}), + frameRate: d.frameRate, + repeat: d.repeat + }); + }) + this.add(sprite); + this.scene.sys.updateList.add(sprite); + this.scene.sys.displayList.add(sprite); + this.sprites.set(texture, sprite); + } this.PlayerValue = name; - this.PlayerTexture = texture; this.playerName = new BitmapText(scene, x, y - 25, 'main_font', name, 8); this.playerName.setOrigin(0.5).setCenterAlign().setDepth(99999); scene.add.existing(this.playerName); - this.scene.sys.updateList.add(this); - this.scene.sys.displayList.add(this); - //this.setScale(2); + scene.add.existing(this); + this.scene.physics.world.enableBody(this); - this.setImmovable(true); - this.setCollideWorldBounds(true); - this.setSize(16, 16); //edit the hitbox to better match the character model - this.setOffset(8, 16); + this.getBody().setImmovable(true); + this.getBody().setCollideWorldBounds(true); + this.setSize(16, 16); + this.getBody().setSize(16, 16); //edit the hitbox to better match the character model + this.getBody().setOffset(0, 8); this.setDepth(-1); this.scene.events.on('postupdate', this.postupdate.bind(this)); - this.initAnimation(); this.playAnimation(direction, moving); } - private initAnimation(): void { - this.getPlayerAnimations(this.PlayerTexture).forEach(d => { - this.scene.anims.create({ - key: d.key, - frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}), - frameRate: d.frameRate, - repeat: d.repeat - }); - }) - } - private getPlayerAnimations(name: string): AnimationData[] { return [{ key: `${name}-${PlayerAnimationNames.WalkDown}`, @@ -122,34 +129,53 @@ export abstract class Character extends Phaser.Physics.Arcade.Sprite { } protected playAnimation(direction : string, moving: boolean): void { - if (!this.anims) { - console.error('ANIMS IS NOT DEFINED!!!'); - return; - } - if (moving && (!this.anims.currentAnim || this.anims.currentAnim.key !== direction)) { - this.play(this.PlayerTexture+'-'+direction, true); - } else if (!moving) { - /*if (this.anims.currentAnim) { - this.anims.stop(); - }*/ - this.play(this.PlayerTexture+'-'+direction, true); - this.stop(); + for (const [texture, sprite] of this.sprites.entries()) { + if (!sprite.anims) { + console.error('ANIMS IS NOT DEFINED!!!'); + return; + } + if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) { + sprite.play(texture+'-'+direction, true); + } else if (!moving) { + /*if (this.anims.currentAnim) { + this.anims.stop(); + }*/ + sprite.play(texture+'-'+direction, true); + sprite.anims.stop(); + } } } - move(x: number, y: number) { + protected getBody(): Phaser.Physics.Arcade.Body { + const body = this.body; + if (!(body instanceof Phaser.Physics.Arcade.Body)) { + throw new Error('Container does not have arcade body'); + } + return body; + } - this.setVelocity(x, y); + move(x: number, y: number) { + const body = this.getBody(); + + body.setVelocity(x, y); // up or down animations are prioritized over left and right - if (this.body.velocity.y < 0) { //moving up - this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkUp}`, true); - } else if (this.body.velocity.y > 0) { //moving down - this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkDown}`, true); - } else if (this.body.velocity.x > 0) { //moving right - this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkRight}`, true); - } else if (this.body.velocity.x < 0) { //moving left - this.anims.playReverse(`${this.PlayerTexture}-${PlayerAnimationNames.WalkLeft}`, true); + if (body.velocity.y < 0) { //moving up + this.lastDirection = PlayerAnimationNames.WalkUp; + this.playAnimation(PlayerAnimationNames.WalkUp, true); + //this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkUp}`, true); + } else if (body.velocity.y > 0) { //moving down + this.lastDirection = PlayerAnimationNames.WalkDown; + this.playAnimation(PlayerAnimationNames.WalkDown, true); + //this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkDown}`, true); + } else if (body.velocity.x > 0) { //moving right + this.lastDirection = PlayerAnimationNames.WalkRight; + this.playAnimation(PlayerAnimationNames.WalkRight, true); + //this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkRight}`, true); + } else if (body.velocity.x < 0) { //moving left + this.lastDirection = PlayerAnimationNames.WalkLeft; + this.playAnimation(PlayerAnimationNames.WalkLeft, true); + //this.anims.playReverse(`${this.PlayerTexture}-${PlayerAnimationNames.WalkLeft}`, true); } if (this.bubble) { @@ -166,8 +192,8 @@ export abstract class Character extends Phaser.Physics.Arcade.Sprite { } stop(){ - this.setVelocity(0, 0); - this.anims.stop(); + this.getBody().setVelocity(0, 0); + this.playAnimation(this.lastDirection, false); } say(text: string) { diff --git a/front/src/Phaser/Entity/RemotePlayer.ts b/front/src/Phaser/Entity/RemotePlayer.ts index 36911bb6..18785331 100644 --- a/front/src/Phaser/Entity/RemotePlayer.ts +++ b/front/src/Phaser/Entity/RemotePlayer.ts @@ -16,11 +16,11 @@ export class RemotePlayer extends Character { x: number, y: number, name: string, - PlayerTexture: string, + PlayerTextures: string[], direction: string, moving: boolean ) { - super(Scene, x, y, PlayerTexture, name, direction, moving, 1); + super(Scene, x, y, PlayerTextures, name, direction, moving, 1); //set data this.userId = userId; diff --git a/front/src/Phaser/Game/AddPlayerInterface.ts b/front/src/Phaser/Game/AddPlayerInterface.ts index 9570c765..a3f50de3 100644 --- a/front/src/Phaser/Game/AddPlayerInterface.ts +++ b/front/src/Phaser/Game/AddPlayerInterface.ts @@ -3,6 +3,6 @@ import {PointInterface} from "../../Connection"; export interface AddPlayerInterface { userId: string; name: string; - character: string; + characterLayers: string[]; position: PointInterface; } diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index f05857b4..3dcf3474 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -42,8 +42,8 @@ export class GameManager { return this.playerName; } - getCharacterSelected(): string { - return this.characterLayers[0]; + getCharacterSelected(): string[] { + return this.characterLayers; } loadMap(mapUrl: string, scene: Phaser.Scenes.ScenePlugin, instance: string): string { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index a46672ee..8034bfbe 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -166,7 +166,7 @@ export class GameScene extends Phaser.Scene { connection.onUserJoins((message: MessageUserJoined) => { const userMessage: AddPlayerInterface = { userId: message.userId, - character: message.character, + characterLayers: message.characterLayers, name: message.name, position: message.position } @@ -704,7 +704,7 @@ export class GameScene extends Phaser.Scene { addPlayerData.position.x, addPlayerData.position.y, addPlayerData.name, - addPlayerData.character, + addPlayerData.characterLayers, addPlayerData.position.direction, addPlayerData.position.moving ); diff --git a/front/src/Phaser/Login/CustomizeScene.ts b/front/src/Phaser/Login/CustomizeScene.ts index fe59e205..7a1dd12e 100644 --- a/front/src/Phaser/Login/CustomizeScene.ts +++ b/front/src/Phaser/Login/CustomizeScene.ts @@ -104,7 +104,7 @@ export class CustomizeScene extends Phaser.Scene { this.input.keyboard.on('keyup-ENTER', () => { const layers: string[] = []; let i = 0; - for (let layerItem of this.selectedLayers) { + for (const layerItem of this.selectedLayers) { console.log(i, layerItem, LAYERS); if (layerItem !== undefined) { layers.push(LAYERS[i][layerItem].name); diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index f912d110..b9490c8d 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -21,17 +21,17 @@ export class Player extends Character implements CurrentGamerInterface { x: number, y: number, name: string, - PlayerTexture: string, + PlayerTextures: string[], direction: string, moving: boolean ) { - super(Scene, x, y, PlayerTexture, name, direction, moving, 1); + super(Scene, x, y, PlayerTextures, name, direction, moving, 1); //create input to move this.userInputManager = new UserInputManager(Scene); //the current player model should be push away by other players to prevent conflict - this.setImmovable(false); + this.getBody().setImmovable(false); } moveUser(delta: number): void {