Propagating customized sprites all over the game

This commit is contained in:
David Négrier 2020-07-28 17:43:33 +02:00
parent 6d0bccc0e1
commit 84529d6e99
14 changed files with 99 additions and 73 deletions

View File

@ -177,7 +177,7 @@ export class IoSocketController {
//add function to refresh position user in real time. //add function to refresh position user in real time.
//this.refreshUserPosition(Client); //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); 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!"); 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 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); }).filter((item: MessageUserPosition|null) => item !== null);
answerFn(listOfUsers); answerFn(listOfUsers);
} catch (e) { } catch (e) {
@ -278,7 +278,7 @@ export class IoSocketController {
} }
const Client = (socket as ExSocketInterface); const Client = (socket as ExSocketInterface);
Client.name = playerDetails.name; Client.name = playerDetails.name;
Client.character = playerDetails.character; Client.characterLayers = playerDetails.characterLayers;
answerFn(Client.userId); answerFn(Client.userId);
}); });
}); });

View File

@ -9,6 +9,6 @@ export interface ExSocketInterface extends Socket, Identificable {
webRtcRoomId: string; webRtcRoomId: string;
userId: string; userId: string;
name: string; name: string;
character: string; characterLayers: string[];
position: PointInterface; position: PointInterface;
} }

View File

@ -1,6 +1,6 @@
import {PointInterface} from "_Model/Websocket/PointInterface"; import {PointInterface} from "_Model/Websocket/PointInterface";
export class MessageUserJoined { 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) {
} }
} }

View File

@ -6,6 +6,6 @@ export class Point implements PointInterface{
} }
export class MessageUserPosition { 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) {
} }
} }

View File

@ -3,6 +3,6 @@ import * as tg from "generic-type-guard";
export const isSetPlayerDetailsMessage = export const isSetPlayerDetailsMessage =
new tg.IsInterface().withProperties({ new tg.IsInterface().withProperties({
name: tg.isString, name: tg.isString,
character: tg.isString characterLayers: tg.isArray(tg.isString)
}).get(); }).get();
export type SetPlayerDetailsMessage = tg.GuardedType<typeof isSetPlayerDetailsMessage>; export type SetPlayerDetailsMessage = tg.GuardedType<typeof isSetPlayerDetailsMessage>;

View File

@ -44,7 +44,7 @@ export class Point implements PointInterface{
export interface MessageUserPositionInterface { export interface MessageUserPositionInterface {
userId: string; userId: string;
name: string; name: string;
character: string; characterLayers: string[];
position: PointInterface; position: PointInterface;
} }
@ -56,7 +56,7 @@ export interface MessageUserMovedInterface {
export interface MessageUserJoined { export interface MessageUserJoined {
userId: string; userId: string;
name: string; name: string;
character: string; characterLayers: string[];
position: PointInterface position: PointInterface
} }
@ -109,7 +109,7 @@ export class Connection implements Connection {
}) })
} }
public static createConnection(name: string, characterSelected: string): Promise<Connection> { public static createConnection(name: string, characterLayersSelected: string[]): Promise<Connection> {
return Axios.post(`${API_URL}/login`, {name: name}) return Axios.post(`${API_URL}/login`, {name: name})
.then((res) => { .then((res) => {
@ -123,7 +123,7 @@ export class Connection implements Connection {
connection.socket.emit(EventMessage.SET_PLAYER_DETAILS, { connection.socket.emit(EventMessage.SET_PLAYER_DETAILS, {
name: name, name: name,
character: characterSelected characterLayers: characterLayersSelected
} as SetPlayerDetailsMessage, (id: string) => { } as SetPlayerDetailsMessage, (id: string) => {
connection.userId = id; connection.userId = id;
}); });
@ -135,7 +135,7 @@ export class Connection implements Connection {
// Let's retry in 4-6 seconds // Let's retry in 4-6 seconds
return new Promise<Connection>((resolve, reject) => { return new Promise<Connection>((resolve, reject) => {
setTimeout(() => { setTimeout(() => {
Connection.createConnection(name, characterSelected).then((connection) => resolve(connection)) Connection.createConnection(name, characterLayersSelected).then((connection) => resolve(connection))
.catch((error) => reject(error)); .catch((error) => reject(error));
}, 4000 + Math.floor(Math.random() * 2000) ); }, 4000 + Math.floor(Math.random() * 2000) );
}); });

View File

@ -1,4 +1,4 @@
export interface SetPlayerDetailsMessage { export interface SetPlayerDetailsMessage {
name: string, name: string,
character: string characterLayers: string[]
} }

View File

@ -1,6 +1,8 @@
import {PlayerAnimationNames} from "../Player/Animation"; import {PlayerAnimationNames} from "../Player/Animation";
import {SpeechBubble} from "./SpeechBubble"; import {SpeechBubble} from "./SpeechBubble";
import BitmapText = Phaser.GameObjects.BitmapText; import BitmapText = Phaser.GameObjects.BitmapText;
import Container = Phaser.GameObjects.Container;
import Sprite = Phaser.GameObjects.Sprite;
export interface PlayerResourceDescriptionInterface { export interface PlayerResourceDescriptionInterface {
name: string, name: string,
@ -38,48 +40,29 @@ interface AnimationData {
frameEnd: number; frameEnd: number;
} }
export abstract class Character extends Phaser.Physics.Arcade.Sprite { export abstract class Character extends Container {
private bubble: SpeechBubble|null = null; private bubble: SpeechBubble|null = null;
private readonly playerName: BitmapText; private readonly playerName: BitmapText;
public PlayerValue: string; public PlayerValue: string;
public PlayerTexture: string; public sprites: Map<string, Sprite>;
private lastDirection: string = PlayerAnimationNames.WalkDown;
constructor(scene: Phaser.Scene, constructor(scene: Phaser.Scene,
x: number, x: number,
y: number, y: number,
texture: string, textures: string[],
name: string, name: string,
direction: string, direction: string,
moving: boolean, moving: boolean,
frame?: string | number frame?: string | number
) { ) {
super(scene, x, y, texture, frame); super(scene, x, y/*, texture, frame*/);
this.PlayerValue = name; this.sprites = new Map<string, Sprite>();
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); for (const texture of textures) {
this.scene.sys.displayList.add(this); const sprite = new Sprite(scene, 0, 0, texture, frame);
//this.setScale(2); this.getPlayerAnimations(texture).forEach(d => {
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.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({ this.scene.anims.create({
key: d.key, key: d.key,
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}), frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}),
@ -87,6 +70,30 @@ export abstract class Character extends Phaser.Physics.Arcade.Sprite {
repeat: d.repeat 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.playerName = new BitmapText(scene, x, y - 25, 'main_font', name, 8);
this.playerName.setOrigin(0.5).setCenterAlign().setDepth(99999);
scene.add.existing(this.playerName);
scene.add.existing(this);
this.scene.physics.world.enableBody(this);
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.playAnimation(direction, moving);
} }
private getPlayerAnimations(name: string): AnimationData[] { private getPlayerAnimations(name: string): AnimationData[] {
@ -122,34 +129,53 @@ export abstract class Character extends Phaser.Physics.Arcade.Sprite {
} }
protected playAnimation(direction : string, moving: boolean): void { protected playAnimation(direction : string, moving: boolean): void {
if (!this.anims) { for (const [texture, sprite] of this.sprites.entries()) {
if (!sprite.anims) {
console.error('ANIMS IS NOT DEFINED!!!'); console.error('ANIMS IS NOT DEFINED!!!');
return; return;
} }
if (moving && (!this.anims.currentAnim || this.anims.currentAnim.key !== direction)) { if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) {
this.play(this.PlayerTexture+'-'+direction, true); sprite.play(texture+'-'+direction, true);
} else if (!moving) { } else if (!moving) {
/*if (this.anims.currentAnim) { /*if (this.anims.currentAnim) {
this.anims.stop(); this.anims.stop();
}*/ }*/
this.play(this.PlayerTexture+'-'+direction, true); sprite.play(texture+'-'+direction, true);
this.stop(); sprite.anims.stop();
} }
} }
}
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;
}
move(x: number, y: number) { move(x: number, y: number) {
const body = this.getBody();
this.setVelocity(x, y); body.setVelocity(x, y);
// up or down animations are prioritized over left and right // up or down animations are prioritized over left and right
if (this.body.velocity.y < 0) { //moving up if (body.velocity.y < 0) { //moving up
this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkUp}`, true); this.lastDirection = PlayerAnimationNames.WalkUp;
} else if (this.body.velocity.y > 0) { //moving down this.playAnimation(PlayerAnimationNames.WalkUp, true);
this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkDown}`, true); //this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkUp}`, true);
} else if (this.body.velocity.x > 0) { //moving right } else if (body.velocity.y > 0) { //moving down
this.play(`${this.PlayerTexture}-${PlayerAnimationNames.WalkRight}`, true); this.lastDirection = PlayerAnimationNames.WalkDown;
} else if (this.body.velocity.x < 0) { //moving left this.playAnimation(PlayerAnimationNames.WalkDown, true);
this.anims.playReverse(`${this.PlayerTexture}-${PlayerAnimationNames.WalkLeft}`, 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) { if (this.bubble) {
@ -166,8 +192,8 @@ export abstract class Character extends Phaser.Physics.Arcade.Sprite {
} }
stop(){ stop(){
this.setVelocity(0, 0); this.getBody().setVelocity(0, 0);
this.anims.stop(); this.playAnimation(this.lastDirection, false);
} }
say(text: string) { say(text: string) {

View File

@ -16,11 +16,11 @@ export class RemotePlayer extends Character {
x: number, x: number,
y: number, y: number,
name: string, name: string,
PlayerTexture: string, PlayerTextures: string[],
direction: string, direction: string,
moving: boolean moving: boolean
) { ) {
super(Scene, x, y, PlayerTexture, name, direction, moving, 1); super(Scene, x, y, PlayerTextures, name, direction, moving, 1);
//set data //set data
this.userId = userId; this.userId = userId;

View File

@ -3,6 +3,6 @@ import {PointInterface} from "../../Connection";
export interface AddPlayerInterface { export interface AddPlayerInterface {
userId: string; userId: string;
name: string; name: string;
character: string; characterLayers: string[];
position: PointInterface; position: PointInterface;
} }

View File

@ -42,8 +42,8 @@ export class GameManager {
return this.playerName; return this.playerName;
} }
getCharacterSelected(): string { getCharacterSelected(): string[] {
return this.characterLayers[0]; return this.characterLayers;
} }
loadMap(mapUrl: string, scene: Phaser.Scenes.ScenePlugin, instance: string): string { loadMap(mapUrl: string, scene: Phaser.Scenes.ScenePlugin, instance: string): string {

View File

@ -166,7 +166,7 @@ export class GameScene extends Phaser.Scene {
connection.onUserJoins((message: MessageUserJoined) => { connection.onUserJoins((message: MessageUserJoined) => {
const userMessage: AddPlayerInterface = { const userMessage: AddPlayerInterface = {
userId: message.userId, userId: message.userId,
character: message.character, characterLayers: message.characterLayers,
name: message.name, name: message.name,
position: message.position position: message.position
} }
@ -704,7 +704,7 @@ export class GameScene extends Phaser.Scene {
addPlayerData.position.x, addPlayerData.position.x,
addPlayerData.position.y, addPlayerData.position.y,
addPlayerData.name, addPlayerData.name,
addPlayerData.character, addPlayerData.characterLayers,
addPlayerData.position.direction, addPlayerData.position.direction,
addPlayerData.position.moving addPlayerData.position.moving
); );

View File

@ -104,7 +104,7 @@ export class CustomizeScene extends Phaser.Scene {
this.input.keyboard.on('keyup-ENTER', () => { this.input.keyboard.on('keyup-ENTER', () => {
const layers: string[] = []; const layers: string[] = [];
let i = 0; let i = 0;
for (let layerItem of this.selectedLayers) { for (const layerItem of this.selectedLayers) {
console.log(i, layerItem, LAYERS); console.log(i, layerItem, LAYERS);
if (layerItem !== undefined) { if (layerItem !== undefined) {
layers.push(LAYERS[i][layerItem].name); layers.push(LAYERS[i][layerItem].name);

View File

@ -21,17 +21,17 @@ export class Player extends Character implements CurrentGamerInterface {
x: number, x: number,
y: number, y: number,
name: string, name: string,
PlayerTexture: string, PlayerTextures: string[],
direction: string, direction: string,
moving: boolean moving: boolean
) { ) {
super(Scene, x, y, PlayerTexture, name, direction, moving, 1); super(Scene, x, y, PlayerTextures, name, direction, moving, 1);
//create input to move //create input to move
this.userInputManager = new UserInputManager(Scene); this.userInputManager = new UserInputManager(Scene);
//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.getBody().setImmovable(false);
} }
moveUser(delta: number): void { moveUser(delta: number): void {