Multi players on the map
authorgparant <g.parant@thecodingmachine.com>
Fri, 10 Apr 2020 10:54:05 +0000 (12:54 +0200)
committergparant <g.parant@thecodingmachine.com>
Fri, 10 Apr 2020 10:54:05 +0000 (12:54 +0200)
 - Fix share user position
 - Fix initialise map
 - Create function to add user on the map with back end data

back/package.json
back/src/Controller/AuthenticateController.ts
back/src/Controller/IoSocketController.ts
back/yarn.lock
front/src/Connexion.ts
front/src/Phaser/Game/GameManager.ts
front/src/Phaser/Game/GameScene.ts
front/src/Phaser/Game/MapManager.ts
front/src/Phaser/Player/Player.ts
front/src/index.ts

index 4fe7681d865623409e73601363249dafbf349e6f..d4bf634926153da55ac9e427cdf79e97108e6cd9 100644 (file)
     "@types/http-status-codes": "^1.2.0",
     "@types/jsonwebtoken": "^8.3.8",
     "@types/socket.io": "^2.1.4",
+    "@types/uuidv4": "^5.0.0",
     "body-parser": "^1.19.0",
     "express": "^4.17.1",
     "http-status-codes": "^1.4.0",
     "jsonwebtoken": "^8.5.1",
     "socket.io": "^2.3.0",
     "ts-node-dev": "^1.0.0-pre.44",
-    "typescript": "^3.8.3"
+    "typescript": "^3.8.3",
+    "uuidv4": "^6.0.7"
   },
   "devDependencies": {
     "@types/jasmine": "^3.5.10",
index 7555c67a502f4d6d136addc410317c893e7ceb01..f9eed470391dd87b2732baf0f5ccdab17920d5c9 100644 (file)
@@ -2,6 +2,7 @@ import {Application, Request, Response} from "express";
 import Jwt from "jsonwebtoken";
 import {BAD_REQUEST, OK} from "http-status-codes";
 import {SECRET_KEY, ROOM} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
+import { uuid } from 'uuidv4';
 
 export class AuthenticateController{
     App : Application;
@@ -21,8 +22,13 @@ export class AuthenticateController{
                 });
             }
             //TODO check user email for The Coding Machine game
-            let token = Jwt.sign({email: param.email, roomId: ROOM}, SECRET_KEY, {expiresIn: '24h'});
-            return res.status(OK).send({token: token, roomId: ROOM});
+            let userId = uuid();
+            let token = Jwt.sign({email: param.email, roomId: ROOM, userId: userId}, SECRET_KEY, {expiresIn: '24h'});
+            return res.status(OK).send({
+                token: token,
+                roomId: ROOM,
+                userId: userId
+            });
         });
     }
 }
\ No newline at end of file
index 24392f09223f04e204761363703fcdd954ef2dda..1fc114a49083ce3631dd0360c82812f1afade598 100644 (file)
@@ -125,8 +125,7 @@ export class IoSocketController{
         }
         arrayMap.forEach((value : any) => {
             let roomId = value[0];
-            let data = value[1];
-            this.Io.in(roomId).emit('user-position', JSON.stringify(data));
+            this.Io.in(roomId).emit('user-position', JSON.stringify(arrayMap));
         });
         this.seTimeOutInProgress = setTimeout(() => {
             this.shareUsersPosition();
index 27f4503ea6525c0108168fcbd1782652b82ce064..4b4f1fe2036342d1c41f49886489072e6406d352 100644 (file)
   resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
   integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
 
+"@types/uuidv4@^5.0.0":
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/@types/uuidv4/-/uuidv4-5.0.0.tgz#2c94e67b0c06d5adb28fb7ced1a1b5f0866ecd50"
+  integrity sha512-xUrhYSJnkTq9CP79cU3svoKTLPCIbMMnu9Twf/tMpHATYSHCAAeDNeb2a/29YORhk5p4atHhCTMsIBU/tvdh6A==
+  dependencies:
+    uuidv4 "*"
+
 "@typescript-eslint/eslint-plugin@^2.26.0":
   version "2.26.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.26.0.tgz#04c96560c8981421e5a9caad8394192363cc423f"
@@ -2094,6 +2101,18 @@ utils-merge@1.0.1:
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
   integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
 
+uuid@7.0.3:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
+  integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
+
+uuidv4@*, uuidv4@^6.0.7:
+  version "6.0.7"
+  resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.0.7.tgz#15e920848e1afbbd97b4919bc50f4f2f2278f880"
+  integrity sha512-4mpYRFNqO22EckzxPSJ/+xjn9GgO6SAqEJ33yt23Y+HZZoZOt/6l4U4iIjc86ZfxSN2fSCGGmHNb3kiACFNd1g==
+  dependencies:
+    uuid "7.0.3"
+
 v8-compile-cache@^2.0.3:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
index d6f09110a02bbb4a366aa150f163f80a2df01393..707d31c4b9c3b85019d5cf4062023366e874a887 100644 (file)
@@ -4,13 +4,7 @@ const SocketIo = require('socket.io-client');
 import Axios from "axios";
 import {API_URL} from "./Enum/EnvironmentVariable";
 
-export interface PointInterface {
-    x: number;
-    y: number;
-    toJson() : object;
-}
-
-export class Message {
+class Message {
     userId: string;
     roomId: string;
 
@@ -27,7 +21,14 @@ export class Message {
     }
 }
 
-export class Point implements PointInterface{
+export interface PointInterface {
+    x: number;
+    y: number;
+    direction : string;
+    toJson() : object;
+}
+
+class Point implements PointInterface{
     x: number;
     y: number;
     direction : string;
@@ -50,7 +51,12 @@ export class Point implements PointInterface{
     }
 }
 
-export class MessageUserPosition extends Message{
+export interface MessageUserPositionInterface {
+    userId: string;
+    roomId: string;
+    position: PointInterface;
+}
+class MessageUserPosition extends Message implements MessageUserPositionInterface{
     position: PointInterface;
 
     constructor(userId : string, roomId : string, point : Point) {
@@ -69,10 +75,36 @@ export class MessageUserPosition extends Message{
     }
 }
 
+export interface ListMessageUserPositionInterface {
+    roomId : string;
+    listUsersPosition: Array<MessageUserPosition>;
+}
+class ListMessageUserPosition{
+    roomId : string;
+    listUsersPosition: Array<MessageUserPosition>;
+
+    constructor(roomId : string, data : any) {
+        this.roomId = roomId;
+        this.listUsersPosition = new Array<MessageUserPosition>();
+        data.forEach((userPosition: any) => {
+            this.listUsersPosition.push(new MessageUserPosition(
+                userPosition.userId,
+                userPosition.roomId,
+                new Point(
+                    userPosition.position.x,
+                    userPosition.position.y,
+                    userPosition.position.direction
+                )
+            ));
+        });
+    }
+}
+
 export class Connexion {
     socket : any;
     token : string;
     email : string;
+    userId: string;
     startedRoom : string;
 
     GameManager: GameManagerInterface;
@@ -80,10 +112,14 @@ export class Connexion {
     constructor(email : string, GameManager: GameManagerInterface) {
         this.email = email;
         this.GameManager = GameManager;
-        Axios.post(`${API_URL}/login`, {email: email})
+    }
+
+    createConnexion(){
+        return Axios.post(`${API_URL}/login`, {email: this.email})
             .then((res) => {
                 this.token = res.data.token;
                 this.startedRoom = res.data.roomId;
+                this.userId = res.data.userId;
 
                 this.socket = SocketIo(`${API_URL}`, {
                     query: {
@@ -100,6 +136,11 @@ export class Connexion {
                 this.positionOfAllUser();
 
                 this.errorMessage();
+
+                return{
+                    userId: this.userId,
+                    roomId: this.startedRoom
+                }
             })
             .catch((err) => {
                 console.error(err);
@@ -112,7 +153,7 @@ export class Connexion {
      * @param roomId
      */
     joinARoom(roomId : string){
-        let messageUserPosition = new MessageUserPosition(this.email, this.startedRoom, new Point(0, 0));
+        let messageUserPosition = new MessageUserPosition(this.userId, this.startedRoom, new Point(0, 0));
         this.socket.emit('join-room', messageUserPosition.toString());
     }
 
@@ -127,7 +168,7 @@ export class Connexion {
         if(!this.socket){
             return;
         }
-        let messageUserPosition = new MessageUserPosition(this.email, roomId, new Point(x, y, direction));
+        let messageUserPosition = new MessageUserPosition(this.userId, roomId, new Point(x, y, direction));
         this.socket.emit('user-position', messageUserPosition.toString());
     }
 
@@ -146,11 +187,12 @@ export class Connexion {
      * ...
      * ]
      **/
-    positionOfAllUser(){
-        this.socket.on("user-position", (message : string) => {
-            let data = JSON.parse(message);
-            data.forEach((UserPositions : any) => {
-                this.GameManager.sharedUserPosition(UserPositions);
+    positionOfAllUser() {
+        this.socket.on("user-position", (message: string) => {
+            let dataList = JSON.parse(message);
+            dataList.forEach((UserPositions: any) => {
+                let listMessageUserPosition = new ListMessageUserPosition(UserPositions[0], UserPositions[1]);
+                this.GameManager.shareUserPosition(listMessageUserPosition);
             });
         });
     }
index ff9f5b5f92764aa821ae4a99ccb7bb971dd67059..2ab1d0d74d6549b31f1f3c74ad3cecd57d7fb09d 100644 (file)
@@ -1,31 +1,76 @@
 import {GameSceneInterface, GameScene} from "./GameScene";
 import {ROOM} from "../../Enum/EnvironmentVariable"
-import {Connexion} from "../../Connexion";
+import {Connexion, ListMessageUserPositionInterface} from "../../Connexion";
+
+export enum StatusGameManagerEnum {
+    IN_PROGRESS = 1,
+    CURRENT_USER_CREATED = 2
+}
 
 export let ConnexionInstance : Connexion;
 
 export interface GameManagerInterface {
     GameScenes: Array<GameSceneInterface>;
-
-    sharedUserPosition(UserPositions: any): void;
+    status : number;
+    createCurrentPlayer() : void;
+    shareUserPosition(ListMessageUserPosition : ListMessageUserPositionInterface): void;
 }
 export class GameManager implements GameManagerInterface {
     GameScenes: Array<GameSceneInterface> = [];
+    status: number;
 
     constructor() {
-        this.configureGame();
+        this.status = StatusGameManagerEnum.IN_PROGRESS;
         ConnexionInstance = new Connexion("test@gmail.com", this);
     }
 
+    createGame(){
+        return ConnexionInstance.createConnexion().then((data: any) => {
+            this.configureGame();
+            /** TODO add loader in the page **/
+        }).catch((err) => {
+            console.error(err);
+            throw err;
+        });
+    }
+
+    /**
+     * permit to config rooms
+     */
     configureGame() {
         ROOM.forEach((roomId) => {
             let newGame = new GameScene(roomId, this);
-            this.GameScenes.push(newGame);
+            this.GameScenes.push((newGame as GameSceneInterface));
         });
     }
 
-    sharedUserPosition(UserPositions: any) {
-        let Game: GameSceneInterface = this.GameScenes.find((Game: GameSceneInterface) => Game.RoomId === UserPositions.roomId);
-        Game.sharedUserPosition(UserPositions)
+    /**
+     * Permit to create player in started room
+     * @param RoomId
+     * @param UserId
+     */
+    createCurrentPlayer(): void {
+        let game: GameSceneInterface = this.GameScenes.find((Game: GameSceneInterface) => Game.RoomId === ConnexionInstance.startedRoom);
+        game.createCurrentPlayer(ConnexionInstance.userId);
+        this.status = StatusGameManagerEnum.CURRENT_USER_CREATED;
+    }
+
+    /**
+     * Share position in game
+     * @param ListMessageUserPosition
+     */
+    shareUserPosition(ListMessageUserPosition: ListMessageUserPositionInterface): void {
+        if (this.status === StatusGameManagerEnum.IN_PROGRESS) {
+            return;
+        }
+        try {
+            let Game: GameSceneInterface = this.GameScenes.find((Game: GameSceneInterface) => Game.RoomId === ListMessageUserPosition.roomId);
+            if (!Game) {
+                return;
+            }
+            Game.shareUserPosition(ListMessageUserPosition.listUsersPosition)
+        } catch (e) {
+            console.error(e);
+        }
     }
 }
\ No newline at end of file
index d3abfd155057fdf5bb116b27d4c2f5935eabdd72..61afdf688a3b1ba4a7b593fa84a180239ba02d5a 100644 (file)
@@ -1,12 +1,15 @@
 import {MapManagerInterface, MapManager} from "./MapManager";
-import {GameManagerInterface} from "./GameManager";
+import {GameManagerInterface, StatusGameManagerEnum} from "./GameManager";
+import {MessageUserPositionInterface} from "../../Connexion";
 
 export interface GameSceneInterface extends Phaser.Scene {
     RoomId : string;
-    sharedUserPosition(data : []): void;
+    createCurrentPlayer(UserId : string) : void;
+    shareUserPosition(UsersPosition : Array<MessageUserPositionInterface>): void;
 }
 export class GameScene extends Phaser.Scene implements GameSceneInterface{
     private MapManager : MapManagerInterface;
+    GameManager : GameManagerInterface;
     RoomId : string;
 
     constructor(RoomId : string, GameManager : GameManagerInterface) {
@@ -14,6 +17,7 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
             key: "GameScene"
         });
         this.RoomId = RoomId;
+        this.GameManager = GameManager;
     }
 
     //hook preload scene
@@ -33,15 +37,31 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface{
     create(): void {
         //create map manager
         this.MapManager = new MapManager(this);
+        //notify game manager can to create currentUser in map
+        this.GameManager.createCurrentPlayer();
+    }
+
+    /**
+     * Create current player
+     * @param UserId
+     */
+    createCurrentPlayer(UserId : string): void {
+        this.MapManager.createCurrentPlayer(UserId)
     }
 
     //hook update
     update(dt: number): void {
+        if(this.GameManager.status === StatusGameManagerEnum.IN_PROGRESS){
+            return;
+        }
         this.MapManager.update();
     }
 
-    sharedUserPosition(data: []): void {
-        //TODO share position of all user
-        //console.log("sharedUserPosition", data);
+    /**
+     * Share position in scene
+     * @param UsersPosition
+     */
+    shareUserPosition(UsersPosition : Array<MessageUserPositionInterface>): void {
+        this.MapManager.updateOrCreateMapPlayer(UsersPosition);
     }
 }
index 8b3d9231e3bdad3c6e9271e404c534d369948208..99ce2863a8cf3d1c20980179c15b8cf3419a066a 100644 (file)
@@ -1,7 +1,8 @@
 import {CameraManager, CameraManagerInterface} from "./CameraManager";
 import {RESOLUTION} from "../../Enum/EnvironmentVariable";
 import {Player} from "../Player/Player";
-import {GameScene, GameSceneInterface} from "./GameScene";
+import {GameSceneInterface} from "./GameScene";
+import {MessageUserPositionInterface} from "../../Connexion";
 
 export interface MapManagerInterface {
     keyZ: Phaser.Input.Keyboard.Key;
@@ -18,7 +19,10 @@ export interface MapManagerInterface {
     Terrain: Phaser.Tilemaps.Tileset;
     Camera: CameraManagerInterface;
     Scene: GameSceneInterface;
+
+    createCurrentPlayer(UserId : string): void;
     update(): void;
+    updateOrCreateMapPlayer(UsersPosition : Array<MessageUserPositionInterface>): void;
 }
 export class MapManager implements MapManagerInterface{
     keyZ: Phaser.Input.Keyboard.Key;
@@ -34,6 +38,7 @@ export class MapManager implements MapManagerInterface{
     Terrain : Phaser.Tilemaps.Tileset;
     Camera: CameraManagerInterface;
     CurrentPlayer: Player;
+    MapPlayers : Player[];
     Scene: GameSceneInterface;
     Map: Phaser.Tilemaps.Tilemap;
     startX = (window.innerWidth / 2) / RESOLUTION;
@@ -51,11 +56,16 @@ export class MapManager implements MapManagerInterface{
 
         //initialise keyboard
         this.initKeyBoard();
-
         //initialise camera
         this.Camera = new CameraManager(this.Scene, this.Scene.cameras.main, this);
+        //initialise list of other player
+        this.MapPlayers = new Array<Player>();
+    }
+
+    createCurrentPlayer(UserId : string){
         //initialise player
         this.CurrentPlayer = new Player(
+            UserId,
             this.Scene,
             this.startX,
             this.startY,
@@ -65,7 +75,6 @@ export class MapManager implements MapManagerInterface{
         this.CurrentPlayer.initAnimation();
     }
 
-
     initKeyBoard() {
         this.keyShift = this.Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT);
 
@@ -83,4 +92,57 @@ export class MapManager implements MapManagerInterface{
     update() : void {
         this.CurrentPlayer.move();
     }
+
+    /**
+     * Create new player and clean the player on the map
+     * @param UsersPosition
+     */
+    updateOrCreateMapPlayer(UsersPosition : Array<MessageUserPositionInterface>){
+        if(!this.CurrentPlayer){
+            return;
+        }
+
+        //add or create new user
+        UsersPosition.forEach((userPosition : MessageUserPositionInterface) => {
+            if(userPosition.userId === this.CurrentPlayer.userId){
+                return;
+            }
+            let player = this.MapPlayers.find((player: Player) => userPosition.userId === player.userId);
+            if(!player){
+                this.addPlayer(userPosition);
+            }else{
+                player.updatePosition(userPosition);
+            }
+        });
+
+        //clean map
+        let mapPlayers = new Array<Player>();
+        this.MapPlayers.forEach((player: Player) => {
+            if(UsersPosition.find((message : MessageUserPositionInterface) => message.userId === player.userId)){
+                mapPlayers.push(player);
+                return;
+            }
+            player.destroy();
+        });
+        this.MapPlayers = mapPlayers;
+    }
+
+    /**
+     * Create new player
+     * @param MessageUserPosition
+     */
+    addPlayer(MessageUserPosition : MessageUserPositionInterface){
+        //initialise player
+        let player = new Player(
+            MessageUserPosition.userId,
+            this.Scene,
+            MessageUserPosition.position.x,
+            MessageUserPosition.position.y,
+            this.Camera,
+            this
+        );
+        player.initAnimation();
+        this.MapPlayers.push(player);
+        player.updatePosition(MessageUserPosition)
+    }
 }
\ No newline at end of file
index 563843fd346ddd2fda886f95657977d1e303c9be..74db636de9378a8ad798121884de4821a8977c55 100644 (file)
@@ -3,13 +3,16 @@ import {getPlayerAnimations, playAnimation, PlayerAnimationNames} from "./Animat
 import {GameSceneInterface} from "../Game/GameScene";
 import {ConnexionInstance} from "../Game/GameManager";
 import {CameraManagerInterface} from "../Game/CameraManager";
+import {MessageUserPositionInterface} from "../../Connexion";
 
 export class Player extends Phaser.GameObjects.Sprite{
+    userId : string;
     MapManager : MapManagerInterface;
     PlayerValue : string;
     CameraManager: CameraManagerInterface;
 
     constructor(
+        userId: string,
         Scene : GameSceneInterface,
         x : number,
         y : number,
@@ -18,13 +21,13 @@ export class Player extends Phaser.GameObjects.Sprite{
         PlayerValue : string = "player"
     ) {
         super(Scene, x, y, PlayerValue);
+        this.userId = userId;
         this.PlayerValue = PlayerValue;
         Scene.add.existing(this);
         this.MapManager = MapManager;
         this.CameraManager = CameraManager;
     }
 
-
     initAnimation(){
         getPlayerAnimations(this.PlayerValue).forEach(d => {
             this.scene.anims.create({
@@ -80,10 +83,9 @@ export class Player extends Phaser.GameObjects.Sprite{
         }
         if(!haveMove){
             playAnimation(this, PlayerAnimationNames.None);
-        }else{
-            this.sharePosition(direction);
+            direction = PlayerAnimationNames.None;
         }
-
+        this.sharePosition(direction);
         this.CameraManager.moveCamera(this);
     }
 
@@ -108,4 +110,10 @@ export class Player extends Phaser.GameObjects.Sprite{
     private CanMoveRight(){
         return this.MapManager.Map.widthInPixels > this.x;
     }
+
+    updatePosition(MessageUserPosition : MessageUserPositionInterface){
+        playAnimation(this, MessageUserPosition.position.direction);
+        this.setX(MessageUserPosition.position.x);
+        this.setY(MessageUserPosition.position.y);
+    }
 }
\ No newline at end of file
index 650fd52cde7bea72555521c3222f48834d12c8da..2a18110d195034af2af01e186c8a1e0f385c6ba2 100644 (file)
@@ -14,8 +14,10 @@ const config: GameConfig = {
     zoom: RESOLUTION,
 };
 
-let game = new Phaser.Game(config);
+gameManager.createGame().then(() => {
+    let game = new Phaser.Game(config);
 
-window.addEventListener('resize', function (event) {
-    game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
+    window.addEventListener('resize', function (event) {
+        game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
+    });
 });