Merge pull request #150 from thecodingmachine/strict_mode_front
Enabling Typescript strict mode on the front
This commit is contained in:
commit
7223c1804d
@ -98,10 +98,10 @@ export interface GroupCreatedUpdatedMessageInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnectionInterface {
|
export interface ConnectionInterface {
|
||||||
socket: any;
|
socket: Socket|null;
|
||||||
token: string;
|
token: string|null;
|
||||||
name: string;
|
name: string|null;
|
||||||
userId: string;
|
userId: string|null;
|
||||||
|
|
||||||
createConnection(name: string, characterSelected: string): Promise<any>;
|
createConnection(name: string, characterSelected: string): Promise<any>;
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ export interface ConnectionInterface {
|
|||||||
sharePosition(x: number, y: number, direction: string, moving: boolean): void;
|
sharePosition(x: number, y: number, direction: string, moving: boolean): void;
|
||||||
|
|
||||||
/*webrtc*/
|
/*webrtc*/
|
||||||
sendWebrtcSignal(signal: any, roomId: string, userId?: string, receiverId?: string): void;
|
sendWebrtcSignal(signal: any, roomId: string, userId?: string|null, receiverId?: string): void;
|
||||||
|
|
||||||
receiveWebrtcSignal(callBack: Function): void;
|
receiveWebrtcSignal(callBack: Function): void;
|
||||||
|
|
||||||
@ -122,15 +122,15 @@ export interface ConnectionInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Connection implements ConnectionInterface {
|
export class Connection implements ConnectionInterface {
|
||||||
socket: Socket;
|
socket: Socket|null = null;
|
||||||
token: string;
|
token: string|null = null;
|
||||||
name: string; // TODO: drop "name" storage here
|
name: string|null = null; // TODO: drop "name" storage here
|
||||||
character: string;
|
character: string|null = null;
|
||||||
userId: string;
|
userId: string|null = null;
|
||||||
|
|
||||||
GameManager: GameManager;
|
GameManager: GameManager;
|
||||||
|
|
||||||
lastPositionShared: PointInterface = null;
|
lastPositionShared: PointInterface|null = null;
|
||||||
lastRoom: string|null = null;
|
lastRoom: string|null = null;
|
||||||
|
|
||||||
constructor(GameManager: GameManager) {
|
constructor(GameManager: GameManager) {
|
||||||
@ -156,6 +156,13 @@ export class Connection implements ConnectionInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSocket(): Socket {
|
||||||
|
if (this.socket === null) {
|
||||||
|
throw new Error('Socket not initialized while using Connection')
|
||||||
|
}
|
||||||
|
return this.socket;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param character
|
* @param character
|
||||||
@ -171,7 +178,7 @@ export class Connection implements ConnectionInterface {
|
|||||||
this.onUserLeft();
|
this.onUserLeft();
|
||||||
|
|
||||||
return new Promise<ConnectionInterface>((resolve, reject) => {
|
return new Promise<ConnectionInterface>((resolve, reject) => {
|
||||||
this.socket.emit(EventMessage.SET_PLAYER_DETAILS, {
|
this.getSocket().emit(EventMessage.SET_PLAYER_DETAILS, {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
character: this.character
|
character: this.character
|
||||||
} as SetPlayerDetailsMessage, (id: string) => {
|
} as SetPlayerDetailsMessage, (id: string) => {
|
||||||
@ -215,7 +222,7 @@ export class Connection implements ConnectionInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean): void {
|
joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean): void {
|
||||||
this.socket.emit(EventMessage.JOIN_ROOM, { roomId, position: {x: startX, y: startY, direction, moving }}, (userPositions: MessageUserPositionInterface[]) => {
|
this.getSocket().emit(EventMessage.JOIN_ROOM, { roomId, position: {x: startX, y: startY, direction, moving }}, (userPositions: MessageUserPositionInterface[]) => {
|
||||||
this.GameManager.initUsersPosition(userPositions);
|
this.GameManager.initUsersPosition(userPositions);
|
||||||
});
|
});
|
||||||
this.lastRoom = roomId;
|
this.lastRoom = roomId;
|
||||||
@ -227,42 +234,42 @@ export class Connection implements ConnectionInterface {
|
|||||||
}
|
}
|
||||||
let point = new Point(x, y, direction, moving);
|
let point = new Point(x, y, direction, moving);
|
||||||
this.lastPositionShared = point;
|
this.lastPositionShared = point;
|
||||||
this.socket.emit(EventMessage.USER_POSITION, point);
|
this.getSocket().emit(EventMessage.USER_POSITION, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUserJoins(): void {
|
private onUserJoins(): void {
|
||||||
this.socket.on(EventMessage.JOIN_ROOM, (message: MessageUserJoined) => {
|
this.getSocket().on(EventMessage.JOIN_ROOM, (message: MessageUserJoined) => {
|
||||||
this.GameManager.onUserJoins(message);
|
this.GameManager.onUserJoins(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUserMoved(): void {
|
private onUserMoved(): void {
|
||||||
this.socket.on(EventMessage.USER_MOVED, (message: MessageUserMovedInterface) => {
|
this.getSocket().on(EventMessage.USER_MOVED, (message: MessageUserMovedInterface) => {
|
||||||
this.GameManager.onUserMoved(message);
|
this.GameManager.onUserMoved(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUserLeft(): void {
|
private onUserLeft(): void {
|
||||||
this.socket.on(EventMessage.USER_LEFT, (userId: string) => {
|
this.getSocket().on(EventMessage.USER_LEFT, (userId: string) => {
|
||||||
this.GameManager.onUserLeft(userId);
|
this.GameManager.onUserLeft(userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private groupUpdatedOrCreated(): void {
|
private groupUpdatedOrCreated(): void {
|
||||||
this.socket.on(EventMessage.GROUP_CREATE_UPDATE, (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => {
|
this.getSocket().on(EventMessage.GROUP_CREATE_UPDATE, (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => {
|
||||||
//console.log('Group ', groupCreateUpdateMessage.groupId, " position :", groupCreateUpdateMessage.position.x, groupCreateUpdateMessage.position.y)
|
//console.log('Group ', groupCreateUpdateMessage.groupId, " position :", groupCreateUpdateMessage.position.x, groupCreateUpdateMessage.position.y)
|
||||||
this.GameManager.shareGroupPosition(groupCreateUpdateMessage);
|
this.GameManager.shareGroupPosition(groupCreateUpdateMessage);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private groupDeleted(): void {
|
private groupDeleted(): void {
|
||||||
this.socket.on(EventMessage.GROUP_DELETE, (groupId: string) => {
|
this.getSocket().on(EventMessage.GROUP_DELETE, (groupId: string) => {
|
||||||
this.GameManager.deleteGroup(groupId);
|
this.GameManager.deleteGroup(groupId);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sendWebrtcSignal(signal: any, roomId: string, userId? : string, receiverId? : string) {
|
sendWebrtcSignal(signal: any, roomId: string, userId? : string|null, receiverId? : string) {
|
||||||
return this.socket.emit(EventMessage.WEBRTC_SIGNAL, {
|
return this.getSocket().emit(EventMessage.WEBRTC_SIGNAL, {
|
||||||
userId: userId ? userId : this.userId,
|
userId: userId ? userId : this.userId,
|
||||||
receiverId: receiverId ? receiverId : this.userId,
|
receiverId: receiverId ? receiverId : this.userId,
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
@ -271,31 +278,34 @@ export class Connection implements ConnectionInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
receiveWebrtcStart(callback: Function) {
|
receiveWebrtcStart(callback: Function) {
|
||||||
this.socket.on(EventMessage.WEBRTC_START, callback);
|
this.getSocket().on(EventMessage.WEBRTC_START, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveWebrtcSignal(callback: Function) {
|
receiveWebrtcSignal(callback: Function) {
|
||||||
return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
|
return this.getSocket().on(EventMessage.WEBRTC_SIGNAL, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private errorMessage(): void {
|
private errorMessage(): void {
|
||||||
this.socket.on(EventMessage.MESSAGE_ERROR, (message: string) => {
|
this.getSocket().on(EventMessage.MESSAGE_ERROR, (message: string) => {
|
||||||
console.error(EventMessage.MESSAGE_ERROR, message);
|
console.error(EventMessage.MESSAGE_ERROR, message);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private disconnectServer(): void {
|
private disconnectServer(): void {
|
||||||
this.socket.on(EventMessage.CONNECT_ERROR, () => {
|
this.getSocket().on(EventMessage.CONNECT_ERROR, () => {
|
||||||
this.GameManager.switchToDisconnectedScene();
|
this.GameManager.switchToDisconnectedScene();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on(EventMessage.RECONNECT, () => {
|
this.getSocket().on(EventMessage.RECONNECT, () => {
|
||||||
this.connectSocketServer();
|
this.connectSocketServer();
|
||||||
|
if (this.lastPositionShared === null) {
|
||||||
|
throw new Error('No last position shared found while reconnecting');
|
||||||
|
}
|
||||||
this.GameManager.reconnectToGameScene(this.lastPositionShared);
|
this.GameManager.reconnectToGameScene(this.lastPositionShared);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectMessage(callback: Function): void {
|
disconnectMessage(callback: Function): void {
|
||||||
this.socket.on(EventMessage.WEBRTC_DISCONNECT, callback);
|
this.getSocket().on(EventMessage.WEBRTC_DISCONNECT, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,18 @@ export class MessageUI {
|
|||||||
static warningMessage(text: string){
|
static warningMessage(text: string){
|
||||||
this.removeMessage();
|
this.removeMessage();
|
||||||
let body = document.getElementById("body");
|
let body = document.getElementById("body");
|
||||||
body.insertAdjacentHTML('afterbegin', `
|
body?.insertAdjacentHTML('afterbegin', `
|
||||||
<div id="message-reconnect" class="message-info warning">
|
<div id="message-reconnect" class="message-info warning">
|
||||||
${text}
|
${text}
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeMessage(id : string = null) {
|
static removeMessage(id : string|null = null) {
|
||||||
if(!id){
|
if(!id){
|
||||||
let messages = document.getElementsByClassName("message-info");
|
let messages = document.getElementsByClassName("message-info");
|
||||||
for (let i = 0; i < messages.length; i++){
|
for (let i = 0; i < messages.length; i++){
|
||||||
messages.item(i).remove();
|
messages.item(i)?.remove();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -24,4 +24,4 @@ export class MessageUI {
|
|||||||
}
|
}
|
||||||
previousElement.remove();
|
previousElement.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,31 @@ export const PLAYER_RESOURCES: Array<any> = [
|
|||||||
{name: "Female8", img: "resources/characters/pipoya/Female 16-4.png"/*, x: 128, y: 128*/}
|
{name: "Female8", img: "resources/characters/pipoya/Female 16-4.png"/*, x: 128, y: 128*/}
|
||||||
];
|
];
|
||||||
|
|
||||||
export class PlayableCaracter extends Phaser.Physics.Arcade.Sprite {
|
interface AnimationData {
|
||||||
private bubble: SpeechBubble;
|
key: string;
|
||||||
|
frameRate: number;
|
||||||
|
repeat: number;
|
||||||
|
frameModel: string; //todo use an enum
|
||||||
|
frameStart: number;
|
||||||
|
frameEnd: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class Character extends Phaser.Physics.Arcade.Sprite {
|
||||||
|
private bubble: SpeechBubble|null = null;
|
||||||
private readonly playerName: BitmapText;
|
private readonly playerName: BitmapText;
|
||||||
public PlayerValue: string;
|
public PlayerValue: string;
|
||||||
public PlayerTexture: string;
|
public PlayerTexture: string;
|
||||||
|
|
||||||
|
|
||||||
constructor(scene: Phaser.Scene, x: number, y: number, texture: string, name: string, frame?: string | number) {
|
constructor(scene: Phaser.Scene,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
texture: string,
|
||||||
|
name: string,
|
||||||
|
direction: string,
|
||||||
|
moving: boolean,
|
||||||
|
frame?: string | number
|
||||||
|
) {
|
||||||
super(scene, x, y, texture, frame);
|
super(scene, x, y, texture, frame);
|
||||||
|
|
||||||
this.PlayerValue = name;
|
this.PlayerValue = name;
|
||||||
@ -51,6 +68,64 @@ export class PlayableCaracter extends Phaser.Physics.Arcade.Sprite {
|
|||||||
this.setDepth(-1);
|
this.setDepth(-1);
|
||||||
|
|
||||||
this.scene.events.on('postupdate', this.postupdate.bind(this));
|
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}`,
|
||||||
|
frameModel: name,
|
||||||
|
frameStart: 0,
|
||||||
|
frameEnd: 2,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: `${name}-${PlayerAnimationNames.WalkLeft}`,
|
||||||
|
frameModel: name,
|
||||||
|
frameStart: 3,
|
||||||
|
frameEnd: 5,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: `${name}-${PlayerAnimationNames.WalkRight}`,
|
||||||
|
frameModel: name,
|
||||||
|
frameStart: 6,
|
||||||
|
frameEnd: 8,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: `${name}-${PlayerAnimationNames.WalkUp}`,
|
||||||
|
frameModel: name,
|
||||||
|
frameStart: 9,
|
||||||
|
frameEnd: 11,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected playAnimation(direction : string, moving: boolean): void {
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
move(x: number, y: number) {
|
move(x: number, y: number) {
|
||||||
@ -91,8 +166,10 @@ export class PlayableCaracter extends Phaser.Physics.Arcade.Sprite {
|
|||||||
this.bubble = new SpeechBubble(this.scene, this, text)
|
this.bubble = new SpeechBubble(this.scene, this, text)
|
||||||
//todo make the bubble destroy on player movement?
|
//todo make the bubble destroy on player movement?
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.bubble.destroy();
|
if (this.bubble !== null) {
|
||||||
this.bubble = null;
|
this.bubble.destroy();
|
||||||
|
this.bubble = null;
|
||||||
|
}
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
38
front/src/Phaser/Entity/RemotePlayer.ts
Normal file
38
front/src/Phaser/Entity/RemotePlayer.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {GameScene} from "../Game/GameScene";
|
||||||
|
import {PointInterface} from "../../Connection";
|
||||||
|
import {Character} from "../Entity/Character";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||||
|
*/
|
||||||
|
export class RemotePlayer extends Character {
|
||||||
|
userId: string;
|
||||||
|
previousDirection: string;
|
||||||
|
wasMoving: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
userId: string,
|
||||||
|
Scene: GameScene,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
name: string,
|
||||||
|
PlayerTexture: string,
|
||||||
|
direction: string,
|
||||||
|
moving: boolean
|
||||||
|
) {
|
||||||
|
super(Scene, x, y, PlayerTexture, name, direction, moving, 1);
|
||||||
|
|
||||||
|
//set data
|
||||||
|
this.userId = userId;
|
||||||
|
|
||||||
|
//the current player model should be push away by other players to prevent conflict
|
||||||
|
//this.setImmovable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition(position: PointInterface): void {
|
||||||
|
this.playAnimation(position.direction, position.moving);
|
||||||
|
this.setX(position.x);
|
||||||
|
this.setY(position.y);
|
||||||
|
this.setDepth(position.y);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import Scene = Phaser.Scene;
|
import Scene = Phaser.Scene;
|
||||||
import {PlayableCaracter} from "./PlayableCaracter";
|
import {Character} from "./Character";
|
||||||
|
|
||||||
export class SpeechBubble {
|
export class SpeechBubble {
|
||||||
private bubble: Phaser.GameObjects.Graphics;
|
private bubble: Phaser.GameObjects.Graphics;
|
||||||
@ -11,7 +11,7 @@ export class SpeechBubble {
|
|||||||
* @param player
|
* @param player
|
||||||
* @param text
|
* @param text
|
||||||
*/
|
*/
|
||||||
constructor(scene: Scene, player: PlayableCaracter, text: string = "") {
|
constructor(scene: Scene, player: Character, text: string = "") {
|
||||||
|
|
||||||
let bubbleHeight = 50;
|
let bubbleHeight = 50;
|
||||||
let bubblePadding = 10;
|
let bubblePadding = 10;
|
||||||
@ -76,13 +76,10 @@ export class SpeechBubble {
|
|||||||
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
|
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.bubble.setVisible(false) //todo find a better way
|
this.bubble.setVisible(false) //todo find a better way
|
||||||
this.bubble.destroy();
|
this.bubble.destroy();
|
||||||
this.bubble = null;
|
|
||||||
this.content.destroy();
|
this.content.destroy();
|
||||||
this.content = null;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
Point,
|
Point,
|
||||||
PointInterface
|
PointInterface
|
||||||
} from "../../Connection";
|
} from "../../Connection";
|
||||||
import {SimplePeerInterface, SimplePeer} from "../../WebRtc/SimplePeer";
|
import {SimplePeer} from "../../WebRtc/SimplePeer";
|
||||||
import {AddPlayerInterface} from "./AddPlayerInterface";
|
import {AddPlayerInterface} from "./AddPlayerInterface";
|
||||||
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
import {ReconnectingSceneName} from "../Reconnecting/ReconnectingScene";
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export class GameManager {
|
|||||||
private ConnectionInstance: Connection;
|
private ConnectionInstance: Connection;
|
||||||
private currentGameScene: GameScene;
|
private currentGameScene: GameScene;
|
||||||
private playerName: string;
|
private playerName: string;
|
||||||
SimplePeer : SimplePeerInterface;
|
SimplePeer : SimplePeer;
|
||||||
private characterUserSelected: string;
|
private characterUserSelected: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -139,7 +139,7 @@ export class GameManager {
|
|||||||
return this.playerName;
|
return this.playerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayerId(): string {
|
getPlayerId(): string|null {
|
||||||
return this.ConnectionInstance.userId;
|
return this.ConnectionInstance.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,9 +155,8 @@ export class GameManager {
|
|||||||
let sceneKey = GameScene.getMapKeyByUrl(mapUrl);
|
let sceneKey = GameScene.getMapKeyByUrl(mapUrl);
|
||||||
|
|
||||||
let gameIndex = scene.getIndex(sceneKey);
|
let gameIndex = scene.getIndex(sceneKey);
|
||||||
let game : Phaser.Scene = null;
|
|
||||||
if(gameIndex === -1){
|
if(gameIndex === -1){
|
||||||
game = GameScene.createFromUrl(mapUrl, instance);
|
let game : Phaser.Scene = GameScene.createFromUrl(mapUrl, instance);
|
||||||
scene.add(sceneKey, game, false);
|
scene.add(sceneKey, game, false);
|
||||||
}
|
}
|
||||||
return sceneKey;
|
return sceneKey;
|
||||||
|
@ -4,10 +4,10 @@ import {
|
|||||||
MessageUserMovedInterface,
|
MessageUserMovedInterface,
|
||||||
MessageUserPositionInterface, PointInterface, PositionInterface
|
MessageUserPositionInterface, PointInterface, PositionInterface
|
||||||
} from "../../Connection";
|
} from "../../Connection";
|
||||||
import {CurrentGamerInterface, GamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
||||||
import { DEBUG_MODE, ZOOM_LEVEL, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
import { DEBUG_MODE, ZOOM_LEVEL, POSITION_DELAY } from "../../Enum/EnvironmentVariable";
|
||||||
import {ITiledMap, ITiledMapLayer, ITiledTileSet} from "../Map/ITiledMap";
|
import {ITiledMap, ITiledMapLayer, ITiledTileSet} from "../Map/ITiledMap";
|
||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/Character";
|
||||||
import Texture = Phaser.Textures.Texture;
|
import Texture = Phaser.Textures.Texture;
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
import CanvasTexture = Phaser.Textures.CanvasTexture;
|
||||||
@ -15,6 +15,7 @@ import {AddPlayerInterface} from "./AddPlayerInterface";
|
|||||||
import {PlayerAnimationNames} from "../Player/Animation";
|
import {PlayerAnimationNames} from "../Player/Animation";
|
||||||
import {PlayerMovement} from "./PlayerMovement";
|
import {PlayerMovement} from "./PlayerMovement";
|
||||||
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
import {PlayersPositionInterpolator} from "./PlayersPositionInterpolator";
|
||||||
|
import {RemotePlayer} from "../Entity/RemotePlayer";
|
||||||
|
|
||||||
export enum Textures {
|
export enum Textures {
|
||||||
Player = "male1"
|
Player = "male1"
|
||||||
@ -29,16 +30,16 @@ export class GameScene extends Phaser.Scene {
|
|||||||
Terrains : Array<Phaser.Tilemaps.Tileset>;
|
Terrains : Array<Phaser.Tilemaps.Tileset>;
|
||||||
CurrentPlayer: CurrentGamerInterface;
|
CurrentPlayer: CurrentGamerInterface;
|
||||||
MapPlayers : Phaser.Physics.Arcade.Group;
|
MapPlayers : Phaser.Physics.Arcade.Group;
|
||||||
MapPlayersByKey : Map<string, GamerInterface> = new Map<string, GamerInterface>();
|
MapPlayersByKey : Map<string, RemotePlayer> = new Map<string, RemotePlayer>();
|
||||||
Map: Phaser.Tilemaps.Tilemap;
|
Map: Phaser.Tilemaps.Tilemap;
|
||||||
Layers : Array<Phaser.Tilemaps.StaticTilemapLayer>;
|
Layers : Array<Phaser.Tilemaps.StaticTilemapLayer>;
|
||||||
Objects : Array<Phaser.Physics.Arcade.Sprite>;
|
Objects : Array<Phaser.Physics.Arcade.Sprite>;
|
||||||
map: ITiledMap;
|
mapFile: ITiledMap;
|
||||||
groups: Map<string, Sprite>;
|
groups: Map<string, Sprite>;
|
||||||
startX = 704;// 22 case
|
startX = 704;// 22 case
|
||||||
startY = 32; // 1 case
|
startY = 32; // 1 case
|
||||||
circleTexture: CanvasTexture;
|
circleTexture: CanvasTexture;
|
||||||
initPosition: PositionInterface;
|
private initPosition: PositionInterface|null = null;
|
||||||
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
private playersPositionInterpolator = new PlayersPositionInterpolator();
|
||||||
|
|
||||||
MapKey: string;
|
MapKey: string;
|
||||||
@ -107,9 +108,9 @@ export class GameScene extends Phaser.Scene {
|
|||||||
private onMapLoad(data: any): void {
|
private onMapLoad(data: any): void {
|
||||||
// Triggered when the map is loaded
|
// Triggered when the map is loaded
|
||||||
// Load tiles attached to the map recursively
|
// Load tiles attached to the map recursively
|
||||||
this.map = data.data;
|
this.mapFile = data.data;
|
||||||
let url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
let url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
|
||||||
this.map.tilesets.forEach((tileset) => {
|
this.mapFile.tilesets.forEach((tileset) => {
|
||||||
if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') {
|
if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') {
|
||||||
console.warn("Don't know how to handle tileset ", tileset)
|
console.warn("Don't know how to handle tileset ", tileset)
|
||||||
return;
|
return;
|
||||||
@ -121,14 +122,16 @@ export class GameScene extends Phaser.Scene {
|
|||||||
|
|
||||||
//hook initialisation
|
//hook initialisation
|
||||||
init(initData : GameSceneInitInterface) {
|
init(initData : GameSceneInitInterface) {
|
||||||
this.initPosition = initData.initPosition;
|
if (initData.initPosition !== undefined) {
|
||||||
|
this.initPosition = initData.initPosition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//hook create scene
|
//hook create scene
|
||||||
create(): void {
|
create(): void {
|
||||||
//initalise map
|
//initalise map
|
||||||
this.Map = this.add.tilemap(this.MapKey);
|
this.Map = this.add.tilemap(this.MapKey);
|
||||||
this.map.tilesets.forEach((tileset: ITiledTileSet) => {
|
this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => {
|
||||||
this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.name));
|
this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.name));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -138,12 +141,12 @@ export class GameScene extends Phaser.Scene {
|
|||||||
//add layer on map
|
//add layer on map
|
||||||
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
|
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
|
||||||
let depth = -2;
|
let depth = -2;
|
||||||
this.map.layers.forEach((layer : ITiledMapLayer) => {
|
this.mapFile.layers.forEach((layer : ITiledMapLayer) => {
|
||||||
if (layer.type === 'tilelayer') {
|
if (layer.type === 'tilelayer') {
|
||||||
this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
|
this.addLayer(this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth));
|
||||||
}
|
}
|
||||||
if (layer.type === 'tilelayer' && this.getExitSceneUrl(layer) !== undefined) {
|
if (layer.type === 'tilelayer' && this.getExitSceneUrl(layer) !== undefined) {
|
||||||
this.loadNextGame(layer, this.map.width, this.map.tilewidth, this.map.tileheight);
|
this.loadNextGame(layer, this.mapFile.width, this.mapFile.tilewidth, this.mapFile.tileheight);
|
||||||
}
|
}
|
||||||
if (layer.type === 'tilelayer' && layer.name === "start") {
|
if (layer.type === 'tilelayer' && layer.name === "start") {
|
||||||
let startPosition = this.startUser(layer);
|
let startPosition = this.startUser(layer);
|
||||||
@ -196,7 +199,7 @@ export class GameScene extends Phaser.Scene {
|
|||||||
// FIXME: entry should be dictated by a property passed to init()
|
// FIXME: entry should be dictated by a property passed to init()
|
||||||
path += '#'+url.hash;
|
path += '#'+url.hash;
|
||||||
}
|
}
|
||||||
window.history.pushState({}, null, path);
|
window.history.pushState({}, 'WorkAdventure', path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
|
private getExitSceneUrl(layer: ITiledMapLayer): string|undefined {
|
||||||
@ -232,6 +235,9 @@ export class GameScene extends Phaser.Scene {
|
|||||||
*/
|
*/
|
||||||
private loadNextGame(layer: ITiledMapLayer, mapWidth: number, tileWidth: number, tileHeight: number){
|
private loadNextGame(layer: ITiledMapLayer, mapWidth: number, tileWidth: number, tileHeight: number){
|
||||||
let exitSceneUrl = this.getExitSceneUrl(layer);
|
let exitSceneUrl = this.getExitSceneUrl(layer);
|
||||||
|
if (exitSceneUrl === undefined) {
|
||||||
|
throw new Error('Layer is not an exit scene layer.');
|
||||||
|
}
|
||||||
let instance = this.getExitSceneInstance(layer);
|
let instance = this.getExitSceneInstance(layer);
|
||||||
if (instance === undefined) {
|
if (instance === undefined) {
|
||||||
instance = this.instance;
|
instance = this.instance;
|
||||||
@ -265,7 +271,7 @@ export class GameScene extends Phaser.Scene {
|
|||||||
* @param layer
|
* @param layer
|
||||||
*/
|
*/
|
||||||
private startUser(layer: ITiledMapLayer): PositionInterface {
|
private startUser(layer: ITiledMapLayer): PositionInterface {
|
||||||
if (this.initPosition !== undefined) {
|
if (this.initPosition !== null) {
|
||||||
this.startX = this.initPosition.x;
|
this.startX = this.initPosition.x;
|
||||||
this.startY = this.initPosition.y;
|
this.startY = this.initPosition.y;
|
||||||
return {
|
return {
|
||||||
@ -338,7 +344,6 @@ export class GameScene extends Phaser.Scene {
|
|||||||
//initialise player
|
//initialise player
|
||||||
//TODO create animation moving between exit and start
|
//TODO create animation moving between exit and start
|
||||||
this.CurrentPlayer = new Player(
|
this.CurrentPlayer = new Player(
|
||||||
null, // The current player is not has no id (because the id can change if connection is lost and we should check that id using the GameManager.
|
|
||||||
this,
|
this,
|
||||||
this.startX,
|
this.startX,
|
||||||
this.startY,
|
this.startY,
|
||||||
@ -413,7 +418,7 @@ export class GameScene extends Phaser.Scene {
|
|||||||
// Let's move all users
|
// Let's move all users
|
||||||
let updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
let updatedPlayersPositions = this.playersPositionInterpolator.getUpdatedPositions(time);
|
||||||
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: string) => {
|
updatedPlayersPositions.forEach((moveEvent: HasMovedEvent, userId: string) => {
|
||||||
let player : GamerInterface | undefined = this.MapPlayersByKey.get(userId);
|
let player : RemotePlayer | undefined = this.MapPlayersByKey.get(userId);
|
||||||
if (player === undefined) {
|
if (player === undefined) {
|
||||||
throw new Error('Cannot find player with ID "' + userId +'"');
|
throw new Error('Cannot find player with ID "' + userId +'"');
|
||||||
}
|
}
|
||||||
@ -450,11 +455,11 @@ export class GameScene extends Phaser.Scene {
|
|||||||
let currentPlayerId = this.GameManager.getPlayerId();
|
let currentPlayerId = this.GameManager.getPlayerId();
|
||||||
|
|
||||||
// clean map
|
// clean map
|
||||||
this.MapPlayersByKey.forEach((player: GamerInterface) => {
|
this.MapPlayersByKey.forEach((player: RemotePlayer) => {
|
||||||
player.destroy();
|
player.destroy();
|
||||||
this.MapPlayers.remove(player);
|
this.MapPlayers.remove(player);
|
||||||
});
|
});
|
||||||
this.MapPlayersByKey = new Map<string, GamerInterface>();
|
this.MapPlayersByKey = new Map<string, RemotePlayer>();
|
||||||
|
|
||||||
// load map
|
// load map
|
||||||
usersPosition.forEach((userPosition : MessageUserPositionInterface) => {
|
usersPosition.forEach((userPosition : MessageUserPositionInterface) => {
|
||||||
@ -478,7 +483,7 @@ export class GameScene extends Phaser.Scene {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//initialise player
|
//initialise player
|
||||||
let player = new Player(
|
let player = new RemotePlayer(
|
||||||
addPlayerData.userId,
|
addPlayerData.userId,
|
||||||
this,
|
this,
|
||||||
addPlayerData.position.x,
|
addPlayerData.position.x,
|
||||||
@ -503,15 +508,16 @@ export class GameScene extends Phaser.Scene {
|
|||||||
let player = this.MapPlayersByKey.get(userId);
|
let player = this.MapPlayersByKey.get(userId);
|
||||||
if (player === undefined) {
|
if (player === undefined) {
|
||||||
console.error('Cannot find user with id ', userId);
|
console.error('Cannot find user with id ', userId);
|
||||||
|
} else {
|
||||||
|
player.destroy();
|
||||||
|
this.MapPlayers.remove(player);
|
||||||
}
|
}
|
||||||
player.destroy();
|
|
||||||
this.MapPlayers.remove(player);
|
|
||||||
this.MapPlayersByKey.delete(userId);
|
this.MapPlayersByKey.delete(userId);
|
||||||
this.playersPositionInterpolator.removePlayer(userId);
|
this.playersPositionInterpolator.removePlayer(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePlayerPosition(message: MessageUserMovedInterface): void {
|
updatePlayerPosition(message: MessageUserMovedInterface): void {
|
||||||
let player : GamerInterface | undefined = this.MapPlayersByKey.get(message.userId);
|
let player : RemotePlayer | undefined = this.MapPlayersByKey.get(message.userId);
|
||||||
if (player === undefined) {
|
if (player === undefined) {
|
||||||
throw new Error('Cannot find player with ID "' + message.userId +'"');
|
throw new Error('Cannot find player with ID "' + message.userId +'"');
|
||||||
}
|
}
|
||||||
@ -525,8 +531,9 @@ export class GameScene extends Phaser.Scene {
|
|||||||
shareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
|
shareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface) {
|
||||||
let groupId = groupPositionMessage.groupId;
|
let groupId = groupPositionMessage.groupId;
|
||||||
|
|
||||||
if (this.groups.has(groupId)) {
|
let group = this.groups.get(groupId);
|
||||||
this.groups.get(groupId).setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
|
if (group !== undefined) {
|
||||||
|
group.setPosition(Math.round(groupPositionMessage.position.x), Math.round(groupPositionMessage.position.y));
|
||||||
} else {
|
} else {
|
||||||
// TODO: circle radius should not be hard stored
|
// TODO: circle radius should not be hard stored
|
||||||
let sprite = new Sprite(
|
let sprite = new Sprite(
|
||||||
@ -541,10 +548,11 @@ export class GameScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteGroup(groupId: string): void {
|
deleteGroup(groupId: string): void {
|
||||||
if(!this.groups.get(groupId)){
|
let group = this.groups.get(groupId);
|
||||||
|
if(!group){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.groups.get(groupId).destroy();
|
group.destroy();
|
||||||
this.groups.delete(groupId);
|
this.groups.delete(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import {TextInput} from "../Components/TextInput";
|
|||||||
import {ClickButton} from "../Components/ClickButton";
|
import {ClickButton} from "../Components/ClickButton";
|
||||||
import Image = Phaser.GameObjects.Image;
|
import Image = Phaser.GameObjects.Image;
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/Character";
|
||||||
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
||||||
import {SelectCharacterSceneInitDataInterface, SelectCharacterSceneName} from "./SelectCharacterScene";
|
import {SelectCharacterSceneInitDataInterface, SelectCharacterSceneName} from "./SelectCharacterScene";
|
||||||
|
|
||||||
@ -16,12 +16,12 @@ enum LoginTextures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LoginScene extends Phaser.Scene {
|
export class LoginScene extends Phaser.Scene {
|
||||||
private nameInput: TextInput;
|
private nameInput: TextInput|null = null;
|
||||||
private textField: TextField;
|
private textField: TextField|null = null;
|
||||||
private infoTextField: TextField;
|
private infoTextField: TextField|null = null;
|
||||||
private pressReturnField: TextField;
|
private pressReturnField: TextField|null = null;
|
||||||
private logo: Image;
|
private logo: Image|null = null;
|
||||||
private name: string;
|
private name: string = '';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
@ -82,9 +82,9 @@ export class LoginScene extends Phaser.Scene {
|
|||||||
|
|
||||||
update(time: number, delta: number): void {
|
update(time: number, delta: number): void {
|
||||||
if (this.name == '') {
|
if (this.name == '') {
|
||||||
this.pressReturnField.setVisible(false);
|
this.pressReturnField?.setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2));
|
this.pressReturnField?.setVisible(!!(Math.floor(time / 500) % 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import {TextField} from "../Components/TextField";
|
|||||||
import {ClickButton} from "../Components/ClickButton";
|
import {ClickButton} from "../Components/ClickButton";
|
||||||
import Image = Phaser.GameObjects.Image;
|
import Image = Phaser.GameObjects.Image;
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/Character";
|
||||||
|
|
||||||
//todo: put this constants in a dedicated file
|
//todo: put this constants in a dedicated file
|
||||||
export const SelectCharacterSceneName = "SelectCharacterScene";
|
export const SelectCharacterSceneName = "SelectCharacterScene";
|
||||||
|
@ -2,39 +2,21 @@ import {PlayerAnimationNames} from "./Animation";
|
|||||||
import {GameScene, Textures} from "../Game/GameScene";
|
import {GameScene, Textures} from "../Game/GameScene";
|
||||||
import {MessageUserPositionInterface, PointInterface} from "../../Connection";
|
import {MessageUserPositionInterface, PointInterface} from "../../Connection";
|
||||||
import {ActiveEventList, UserInputEvent, UserInputManager} from "../UserInput/UserInputManager";
|
import {ActiveEventList, UserInputEvent, UserInputManager} from "../UserInput/UserInputManager";
|
||||||
import {PlayableCaracter} from "../Entity/PlayableCaracter";
|
import {Character} from "../Entity/Character";
|
||||||
|
|
||||||
|
|
||||||
export const hasMovedEventName = "hasMoved";
|
export const hasMovedEventName = "hasMoved";
|
||||||
export interface CurrentGamerInterface extends PlayableCaracter{
|
export interface CurrentGamerInterface extends Character{
|
||||||
moveUser(delta: number) : void;
|
moveUser(delta: number) : void;
|
||||||
say(text : string) : void;
|
say(text : string) : void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GamerInterface extends PlayableCaracter{
|
export class Player extends Character implements CurrentGamerInterface {
|
||||||
userId : string;
|
|
||||||
updatePosition(position: PointInterface): void;
|
|
||||||
say(text : string) : void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AnimationData {
|
|
||||||
key: string;
|
|
||||||
frameRate: number;
|
|
||||||
repeat: number;
|
|
||||||
frameModel: string; //todo use an enum
|
|
||||||
frameStart: number;
|
|
||||||
frameEnd: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class Player extends PlayableCaracter implements CurrentGamerInterface, GamerInterface {
|
|
||||||
userId: string;
|
|
||||||
userInputManager: UserInputManager;
|
userInputManager: UserInputManager;
|
||||||
previousDirection: string;
|
previousDirection: string;
|
||||||
wasMoving: boolean;
|
wasMoving: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
userId: string,
|
|
||||||
Scene: GameScene,
|
Scene: GameScene,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
@ -43,62 +25,13 @@ export class Player extends PlayableCaracter implements CurrentGamerInterface, G
|
|||||||
direction: string,
|
direction: string,
|
||||||
moving: boolean
|
moving: boolean
|
||||||
) {
|
) {
|
||||||
super(Scene, x, y, PlayerTexture, name, 1);
|
super(Scene, x, y, PlayerTexture, name, direction, moving, 1);
|
||||||
|
|
||||||
//create input to move
|
//create input to move
|
||||||
this.userInputManager = new UserInputManager(Scene);
|
this.userInputManager = new UserInputManager(Scene);
|
||||||
|
|
||||||
//set data
|
|
||||||
this.userId = userId;
|
|
||||||
|
|
||||||
//the current player model should be push away by other players to prevent conflict
|
//the current player model should be push away by other players to prevent conflict
|
||||||
this.setImmovable(false);
|
this.setImmovable(false);
|
||||||
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}`,
|
|
||||||
frameModel: name,
|
|
||||||
frameStart: 0,
|
|
||||||
frameEnd: 2,
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
}, {
|
|
||||||
key: `${name}-${PlayerAnimationNames.WalkLeft}`,
|
|
||||||
frameModel: name,
|
|
||||||
frameStart: 3,
|
|
||||||
frameEnd: 5,
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
}, {
|
|
||||||
key: `${name}-${PlayerAnimationNames.WalkRight}`,
|
|
||||||
frameModel: name,
|
|
||||||
frameStart: 6,
|
|
||||||
frameEnd: 8,
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
}, {
|
|
||||||
key: `${name}-${PlayerAnimationNames.WalkUp}`,
|
|
||||||
frameModel: name,
|
|
||||||
frameStart: 9,
|
|
||||||
frameEnd: 11,
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moveUser(delta: number): void {
|
moveUser(delta: number): void {
|
||||||
@ -146,24 +79,4 @@ export class Player extends PlayableCaracter implements CurrentGamerInterface, G
|
|||||||
}
|
}
|
||||||
this.wasMoving = moving;
|
this.wasMoving = moving;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: put this method into the NonPlayer class instead
|
|
||||||
updatePosition(position: PointInterface): void {
|
|
||||||
this.playAnimation(position.direction, position.moving);
|
|
||||||
this.setX(position.x);
|
|
||||||
this.setY(position.y);
|
|
||||||
this.setDepth(position.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private playAnimation(direction : string, moving: boolean): void {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import {TextInput} from "../Components/TextInput";
|
|||||||
import {ClickButton} from "../Components/ClickButton";
|
import {ClickButton} from "../Components/ClickButton";
|
||||||
import Image = Phaser.GameObjects.Image;
|
import Image = Phaser.GameObjects.Image;
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
import Rectangle = Phaser.GameObjects.Rectangle;
|
||||||
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
|
import {PLAYER_RESOURCES} from "../Entity/Character";
|
||||||
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
||||||
import Sprite = Phaser.GameObjects.Sprite;
|
import Sprite = Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ import Map = Phaser.Structs.Map;
|
|||||||
import {GameScene} from "../Game/GameScene";
|
import {GameScene} from "../Game/GameScene";
|
||||||
|
|
||||||
interface UserInputManagerDatum {
|
interface UserInputManagerDatum {
|
||||||
keyCode: number;
|
|
||||||
keyInstance: Phaser.Input.Keyboard.Key;
|
keyInstance: Phaser.Input.Keyboard.Key;
|
||||||
event: UserInputEvent
|
event: UserInputEvent
|
||||||
}
|
}
|
||||||
@ -33,27 +32,26 @@ export class ActiveEventList {
|
|||||||
|
|
||||||
//this class is responsible for catching user inputs and listing all active user actions at every game tick events.
|
//this class is responsible for catching user inputs and listing all active user actions at every game tick events.
|
||||||
export class UserInputManager {
|
export class UserInputManager {
|
||||||
private KeysCode: UserInputManagerDatum[] = [
|
private KeysCode: UserInputManagerDatum[];
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.Z, event: UserInputEvent.MoveUp, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.Q, event: UserInputEvent.MoveLeft, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.S, event: UserInputEvent.MoveDown, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.D, event: UserInputEvent.MoveRight, keyInstance: null},
|
|
||||||
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.UP, event: UserInputEvent.MoveUp, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.LEFT, event: UserInputEvent.MoveLeft, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.DOWN, event: UserInputEvent.MoveDown, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.RIGHT, event: UserInputEvent.MoveRight, keyInstance: null},
|
|
||||||
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.SHIFT, event: UserInputEvent.SpeedUp, keyInstance: null},
|
|
||||||
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.E, event: UserInputEvent.Interact, keyInstance: null},
|
|
||||||
{keyCode: Phaser.Input.Keyboard.KeyCodes.F, event: UserInputEvent.Shout, keyInstance: null},
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(Scene : GameScene) {
|
constructor(Scene : GameScene) {
|
||||||
this.KeysCode.forEach(d => {
|
|
||||||
d.keyInstance = Scene.input.keyboard.addKey(d.keyCode);
|
this.KeysCode = [
|
||||||
});
|
{event: UserInputEvent.MoveUp, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z) },
|
||||||
|
{event: UserInputEvent.MoveLeft, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q) },
|
||||||
|
{event: UserInputEvent.MoveDown, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S) },
|
||||||
|
{event: UserInputEvent.MoveRight, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D) },
|
||||||
|
|
||||||
|
{event: UserInputEvent.MoveUp, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP) },
|
||||||
|
{event: UserInputEvent.MoveLeft, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT) },
|
||||||
|
{event: UserInputEvent.MoveDown, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN) },
|
||||||
|
{event: UserInputEvent.MoveRight, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT) },
|
||||||
|
|
||||||
|
{event: UserInputEvent.SpeedUp, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT) },
|
||||||
|
|
||||||
|
{event: UserInputEvent.Interact, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E) },
|
||||||
|
{event: UserInputEvent.Shout, keyInstance: Scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F) },
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
getEventListForGameTick(): ActiveEventList {
|
getEventListForGameTick(): ActiveEventList {
|
||||||
|
@ -4,26 +4,25 @@ const videoConstraint: {width : any, height: any, facingMode : string} = {
|
|||||||
facingMode: "user"
|
facingMode: "user"
|
||||||
};
|
};
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
localStream: MediaStream;
|
localStream: MediaStream|null = null;
|
||||||
remoteVideo: Array<any> = new Array<any>();
|
remoteVideo: Array<any> = new Array<any>();
|
||||||
myCamVideo: any;
|
myCamVideo: HTMLVideoElement;
|
||||||
cinemaClose: any = null;
|
cinemaClose: any = null;
|
||||||
cinema: any = null;
|
cinema: any = null;
|
||||||
microphoneClose: any = null;
|
microphoneClose: any = null;
|
||||||
microphone: any = null;
|
microphone: any = null;
|
||||||
webrtcInAudio: any;
|
webrtcInAudio: HTMLAudioElement;
|
||||||
constraintsMedia : {audio : any, video : any} = {
|
constraintsMedia : {audio : any, video : any} = {
|
||||||
audio: true,
|
audio: true,
|
||||||
video: videoConstraint
|
video: videoConstraint
|
||||||
};
|
};
|
||||||
getCameraPromise : Promise<any> = null;
|
|
||||||
updatedLocalStreamCallBack : Function;
|
updatedLocalStreamCallBack : Function;
|
||||||
|
|
||||||
constructor(updatedLocalStreamCallBack : Function) {
|
constructor(updatedLocalStreamCallBack : Function) {
|
||||||
this.updatedLocalStreamCallBack = updatedLocalStreamCallBack;
|
this.updatedLocalStreamCallBack = updatedLocalStreamCallBack;
|
||||||
|
|
||||||
this.myCamVideo = document.getElementById('myCamVideo');
|
this.myCamVideo = this.getElementByIdOrFail<HTMLVideoElement>('myCamVideo');
|
||||||
this.webrtcInAudio = document.getElementById('audio-webrtc-in');
|
this.webrtcInAudio = this.getElementByIdOrFail<HTMLAudioElement>('audio-webrtc-in');
|
||||||
this.webrtcInAudio.volume = 0.2;
|
this.webrtcInAudio.volume = 0.2;
|
||||||
|
|
||||||
this.microphoneClose = document.getElementById('microphone-close');
|
this.microphoneClose = document.getElementById('microphone-close');
|
||||||
@ -56,7 +55,7 @@ export class MediaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
activeVisio(){
|
activeVisio(){
|
||||||
let webRtc = document.getElementById('webRtc');
|
let webRtc = this.getElementByIdOrFail('webRtc');
|
||||||
webRtc.classList.add('active');
|
webRtc.classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +129,7 @@ export class MediaManager {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
promise = Promise.reject(false);
|
promise = Promise.reject(false);
|
||||||
}
|
}
|
||||||
return this.getCameraPromise = promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,7 +138,7 @@ export class MediaManager {
|
|||||||
*/
|
*/
|
||||||
addActiveVideo(userId : string, userName: string = ""){
|
addActiveVideo(userId : string, userName: string = ""){
|
||||||
this.webrtcInAudio.play();
|
this.webrtcInAudio.play();
|
||||||
let elementRemoteVideo = document.getElementById("activeCam");
|
let elementRemoteVideo = this.getElementByIdOrFail("activeCam");
|
||||||
userName = userName.toUpperCase();
|
userName = userName.toUpperCase();
|
||||||
let color = this.getColorByString(userName);
|
let color = this.getColorByString(userName);
|
||||||
elementRemoteVideo.insertAdjacentHTML('beforeend', `
|
elementRemoteVideo.insertAdjacentHTML('beforeend', `
|
||||||
@ -247,4 +246,14 @@ export class MediaManager {
|
|||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private getElementByIdOrFail<T extends HTMLElement>(id: string): T {
|
||||||
|
let elem = document.getElementById(id);
|
||||||
|
if (elem === null) {
|
||||||
|
throw new Error("Cannot find HTML element with id '"+id+"'");
|
||||||
|
}
|
||||||
|
// FIXME: does not check the type of the returned type
|
||||||
|
return elem as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import {ConnectionInterface} from "../Connection";
|
import {ConnectionInterface} from "../Connection";
|
||||||
import {MediaManager} from "./MediaManager";
|
import {MediaManager} from "./MediaManager";
|
||||||
let Peer = require('simple-peer');
|
import * as SimplePeerNamespace from "simple-peer";
|
||||||
|
let Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
|
||||||
|
|
||||||
class UserSimplePear{
|
class UserSimplePeer{
|
||||||
userId: string;
|
userId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
initiator?: boolean;
|
initiator?: boolean;
|
||||||
}
|
}
|
||||||
export class SimplePeerInterface {}
|
export class SimplePeer {
|
||||||
export class SimplePeer implements SimplePeerInterface{
|
|
||||||
private Connection: ConnectionInterface;
|
private Connection: ConnectionInterface;
|
||||||
private WebRtcRoomId: string;
|
private WebRtcRoomId: string;
|
||||||
private Users: Array<UserSimplePear> = new Array<UserSimplePear>();
|
private Users: Array<UserSimplePeer> = new Array<UserSimplePeer>();
|
||||||
|
|
||||||
private MediaManager: MediaManager;
|
private MediaManager: MediaManager;
|
||||||
|
|
||||||
private PeerConnectionArray: Map<string, any> = new Map<string, any>();
|
private PeerConnectionArray: Map<string, SimplePeerNamespace.Instance> = new Map<string, SimplePeerNamespace.Instance>();
|
||||||
|
|
||||||
constructor(Connection: ConnectionInterface, WebRtcRoomId: string = "test-webrtc") {
|
constructor(Connection: ConnectionInterface, WebRtcRoomId: string = "test-webrtc") {
|
||||||
this.Connection = Connection;
|
this.Connection = Connection;
|
||||||
@ -66,7 +66,7 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
* server has two person connected, start the meet
|
* server has two person connected, start the meet
|
||||||
*/
|
*/
|
||||||
private startWebRtc() {
|
private startWebRtc() {
|
||||||
this.Users.forEach((user: UserSimplePear) => {
|
this.Users.forEach((user: UserSimplePeer) => {
|
||||||
//if it's not an initiator, peer connection will be created when gamer will receive offer signal
|
//if it's not an initiator, peer connection will be created when gamer will receive offer signal
|
||||||
if(!user.initiator){
|
if(!user.initiator){
|
||||||
return;
|
return;
|
||||||
@ -78,14 +78,14 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
/**
|
/**
|
||||||
* create peer connection to bind users
|
* create peer connection to bind users
|
||||||
*/
|
*/
|
||||||
private createPeerConnection(user : UserSimplePear) {
|
private createPeerConnection(user : UserSimplePeer) {
|
||||||
if(this.PeerConnectionArray.has(user.userId)) {
|
if(this.PeerConnectionArray.has(user.userId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = user.name;
|
let name = user.name;
|
||||||
if(!name){
|
if(!name){
|
||||||
let userSearch = this.Users.find((userSearch: UserSimplePear) => userSearch.userId === user.userId);
|
let userSearch = this.Users.find((userSearch: UserSimplePeer) => userSearch.userId === user.userId);
|
||||||
if(userSearch) {
|
if(userSearch) {
|
||||||
name = userSearch.name;
|
name = userSearch.name;
|
||||||
}
|
}
|
||||||
@ -112,11 +112,11 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
this.PeerConnectionArray.set(user.userId, peer);
|
this.PeerConnectionArray.set(user.userId, peer);
|
||||||
|
|
||||||
//start listen signal for the peer connection
|
//start listen signal for the peer connection
|
||||||
this.PeerConnectionArray.get(user.userId).on('signal', (data: any) => {
|
peer.on('signal', (data: any) => {
|
||||||
this.sendWebrtcSignal(data, user.userId);
|
this.sendWebrtcSignal(data, user.userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.PeerConnectionArray.get(user.userId).on('stream', (stream: MediaStream) => {
|
peer.on('stream', (stream: MediaStream) => {
|
||||||
let videoActive = false;
|
let videoActive = false;
|
||||||
let microphoneActive = false;
|
let microphoneActive = false;
|
||||||
stream.getTracks().forEach((track : MediaStreamTrack) => {
|
stream.getTracks().forEach((track : MediaStreamTrack) => {
|
||||||
@ -141,23 +141,23 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
this.stream(user.userId, stream);
|
this.stream(user.userId, stream);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*this.PeerConnectionArray.get(user.userId).on('track', (track: MediaStreamTrack, stream: MediaStream) => {
|
/*peer.on('track', (track: MediaStreamTrack, stream: MediaStream) => {
|
||||||
this.stream(user.userId, stream);
|
this.stream(user.userId, stream);
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
this.PeerConnectionArray.get(user.userId).on('close', () => {
|
peer.on('close', () => {
|
||||||
this.closeConnection(user.userId);
|
this.closeConnection(user.userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.PeerConnectionArray.get(user.userId).on('error', (err: any) => {
|
peer.on('error', (err: any) => {
|
||||||
console.error(`error => ${user.userId} => ${err.code}`, err);
|
console.error(`error => ${user.userId} => ${err.code}`, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.PeerConnectionArray.get(user.userId).on('connect', () => {
|
peer.on('connect', () => {
|
||||||
console.info(`connect => ${user.userId}`);
|
console.info(`connect => ${user.userId}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.PeerConnectionArray.get(user.userId).on('data', (chunk: Buffer) => {
|
peer.on('data', (chunk: Buffer) => {
|
||||||
let data = JSON.parse(chunk.toString('utf8'));
|
let data = JSON.parse(chunk.toString('utf8'));
|
||||||
if(data.type === "stream"){
|
if(data.type === "stream"){
|
||||||
this.stream(user.userId, data.stream);
|
this.stream(user.userId, data.stream);
|
||||||
@ -174,7 +174,7 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.PeerConnectionArray.get(userId).destroy();
|
this.PeerConnectionArray.get(userId)?.destroy();
|
||||||
this.PeerConnectionArray.delete(userId)
|
this.PeerConnectionArray.delete(userId)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("closeConnection", err)
|
console.error("closeConnection", err)
|
||||||
@ -200,7 +200,12 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
if(data.signal.type === "offer"){
|
if(data.signal.type === "offer"){
|
||||||
this.createPeerConnection(data);
|
this.createPeerConnection(data);
|
||||||
}
|
}
|
||||||
this.PeerConnectionArray.get(data.userId).signal(data.signal);
|
let peer = this.PeerConnectionArray.get(data.userId);
|
||||||
|
if (peer !== undefined) {
|
||||||
|
peer.signal(data.signal);
|
||||||
|
} else {
|
||||||
|
console.error('Could not find peer whose ID is "'+data.userId+'" in PeerConnectionArray');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
|
console.error(`receiveWebrtcSignal => ${data.userId}`, e);
|
||||||
}
|
}
|
||||||
@ -227,27 +232,32 @@ export class SimplePeer implements SimplePeerInterface{
|
|||||||
private addMedia (userId : any = null) {
|
private addMedia (userId : any = null) {
|
||||||
try {
|
try {
|
||||||
let transceiver : any = null;
|
let transceiver : any = null;
|
||||||
if(!this.MediaManager.localStream){
|
let localStream: MediaStream|null = this.MediaManager.localStream;
|
||||||
|
let peer = this.PeerConnectionArray.get(userId);
|
||||||
|
if(localStream === null) {
|
||||||
//send fake signal
|
//send fake signal
|
||||||
if(!this.PeerConnectionArray.has(userId)){
|
if(peer === undefined){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.PeerConnectionArray.get(userId).write(new Buffer(JSON.stringify({
|
peer.write(new Buffer(JSON.stringify({
|
||||||
type: "stream",
|
type: "stream",
|
||||||
stream: null
|
stream: null
|
||||||
})));
|
})));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.MediaManager.localStream.getTracks().forEach(
|
if (peer === undefined) {
|
||||||
transceiver = (track: MediaStreamTrack) => this.PeerConnectionArray.get(userId).addTrack(track, this.MediaManager.localStream)
|
throw new Error('While adding media, cannot find user with ID '+userId);
|
||||||
)
|
}
|
||||||
|
for (const track of localStream.getTracks()) {
|
||||||
|
peer.addTrack(track, localStream);
|
||||||
|
}
|
||||||
}catch (e) {
|
}catch (e) {
|
||||||
console.error(`addMedia => addMedia => ${userId}`, e);
|
console.error(`addMedia => addMedia => ${userId}`, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedLocalStream(){
|
updatedLocalStream(){
|
||||||
this.Users.forEach((user: UserSimplePear) => {
|
this.Users.forEach((user: UserSimplePeer) => {
|
||||||
this.addMedia(user.userId);
|
this.addMedia(user.userId);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,18 @@
|
|||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"allowJs": true
|
"allowJs": true,
|
||||||
|
|
||||||
|
"strict": false, /* Enable all strict type-checking options. */
|
||||||
|
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
|
"strictNullChecks": true, /* Enable strict null checks. */
|
||||||
|
"strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
|
"strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
|
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
|
||||||
|
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
|
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
|
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
|
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user