Plugin PositionNotifier into the main application.
This commit is contained in:
parent
f8d462b0d7
commit
d24ec0bd75
@ -20,6 +20,7 @@ import {isWebRtcSignalMessageInterface} from "../Model/Websocket/WebRtcSignalMes
|
||||
import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface";
|
||||
import {uuid} from 'uuidv4';
|
||||
import {isUserMovesInterface} from "../Model/Websocket/UserMovesMessage";
|
||||
import {isViewport} from "../Model/Websocket/ViewportMessage";
|
||||
|
||||
enum SockerIoEvent {
|
||||
CONNECTION = "connection",
|
||||
@ -212,22 +213,16 @@ export class IoSocketController {
|
||||
//join new previous room
|
||||
const world = this.joinRoom(Client, roomId, message.position);
|
||||
|
||||
//add function to refresh position user in real time.
|
||||
//this.refreshUserPosition(Client);
|
||||
|
||||
const messageUserJoined = new MessageUserJoined(Client.userId, Client.name, Client.characterLayers, Client.position);
|
||||
|
||||
socket.to(roomId).emit(SockerIoEvent.JOIN_ROOM, messageUserJoined);
|
||||
|
||||
// The answer shall contain the list of all users of the room with their positions:
|
||||
const listOfUsers = Array.from(world.getUsers(), ([key, user]) => {
|
||||
const users = world.setViewport(Client, message.viewport);
|
||||
const listOfUsers = users.map((user: UserInterface) => {
|
||||
const player: ExSocketInterface|undefined = this.sockets.get(user.id);
|
||||
if (player === undefined) {
|
||||
console.warn('Something went wrong. The World contains a user "'+user.id+"' but this user does not exist in the sockets list!");
|
||||
return null;
|
||||
}
|
||||
return new MessageUserPosition(user.id, player.name, player.characterLayers, player.position);
|
||||
}).filter((item: MessageUserPosition|null) => item !== null);
|
||||
}, users);
|
||||
|
||||
answerFn(listOfUsers);
|
||||
} catch (e) {
|
||||
console.error('An error occurred on "join_room" event');
|
||||
@ -235,6 +230,30 @@ export class IoSocketController {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on(SockerIoEvent.SET_VIEWPORT, (message: unknown): void => {
|
||||
try {
|
||||
//console.log('SET_VIEWPORT')
|
||||
if (!isViewport(message)) {
|
||||
socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid SET_VIEWPORT message.'});
|
||||
console.warn('Invalid SET_VIEWPORT message received: ', message);
|
||||
return;
|
||||
}
|
||||
|
||||
const Client = (socket as ExSocketInterface);
|
||||
Client.viewport = message;
|
||||
|
||||
const world = this.Worlds.get(Client.roomId);
|
||||
if (!world) {
|
||||
console.error("Could not find world with id '", Client.roomId, "'");
|
||||
return;
|
||||
}
|
||||
world.setViewport(Client, Client.viewport);
|
||||
} catch (e) {
|
||||
console.error('An error occurred on "SET_VIEWPORT" event');
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on(SockerIoEvent.USER_POSITION, (userMovesMessage: unknown): void => {
|
||||
console.log(SockerIoEvent.USER_POSITION, userMovesMessage);
|
||||
try {
|
||||
@ -257,19 +276,7 @@ export class IoSocketController {
|
||||
return;
|
||||
}
|
||||
world.updatePosition(Client, Client.position);
|
||||
|
||||
const clientsInRoom = this.Io.sockets.adapter.rooms[Client.roomId];
|
||||
console.log('clientsInRoom', clientsInRoom);
|
||||
for (const clientId in clientsInRoom.sockets) {
|
||||
console.log('client: %s', clientId);
|
||||
const targetSocket = this.Io.sockets.connected[clientId] as ExSocketInterface;
|
||||
if (socket === targetSocket) {
|
||||
continue;
|
||||
}
|
||||
//targetSocket.emit(SockerIoEvent.USER_MOVED, new MessageUserMoved(Client.userId, Client.position));
|
||||
targetSocket.emitInBatch(SockerIoEvent.USER_MOVED, new MessageUserMoved(Client.userId, Client.position));
|
||||
}
|
||||
//socket.to(Client.roomId).emit(SockerIoEvent.USER_MOVED, new MessageUserMoved(Client.userId, Client.position));
|
||||
world.setViewport(Client, Client.viewport);
|
||||
} catch (e) {
|
||||
console.error('An error occurred on "user_position" event');
|
||||
console.error(e);
|
||||
@ -404,8 +411,6 @@ export class IoSocketController {
|
||||
// leave previous room and world
|
||||
if(Client.roomId){
|
||||
try {
|
||||
Client.to(Client.roomId).emit(SockerIoEvent.USER_LEFT, Client.userId);
|
||||
|
||||
//user leave previous world
|
||||
const world: World | undefined = this.Worlds.get(Client.roomId);
|
||||
if (world) {
|
||||
@ -441,6 +446,25 @@ export class IoSocketController {
|
||||
this.sendUpdateGroupEvent(group);
|
||||
}, (groupUuid: string, lastUser: UserInterface) => {
|
||||
this.sendDeleteGroupEvent(groupUuid, lastUser);
|
||||
}, (user, listener) => {
|
||||
const clientUser = this.searchClientByIdOrFail(user.id);
|
||||
const clientListener = this.searchClientByIdOrFail(listener.id);
|
||||
const messageUserJoined = new MessageUserJoined(clientUser.userId, clientUser.name, clientUser.characterLayers, clientUser.position);
|
||||
|
||||
clientListener.emit(SockerIoEvent.JOIN_ROOM, messageUserJoined);
|
||||
//console.log("Sending JOIN_ROOM event");
|
||||
}, (user, position, listener) => {
|
||||
const clientUser = this.searchClientByIdOrFail(user.id);
|
||||
const clientListener = this.searchClientByIdOrFail(listener.id);
|
||||
|
||||
clientListener.emitInBatch(SockerIoEvent.USER_MOVED, new MessageUserMoved(clientUser.userId, clientUser.position));
|
||||
//console.log("Sending USER_MOVED event");
|
||||
}, (user, listener) => {
|
||||
const clientUser = this.searchClientByIdOrFail(user.id);
|
||||
const clientListener = this.searchClientByIdOrFail(listener.id);
|
||||
|
||||
clientListener.emit(SockerIoEvent.USER_LEFT, clientUser.userId);
|
||||
//console.log("Sending USER_LEFT event");
|
||||
});
|
||||
this.Worlds.set(roomId, world);
|
||||
}
|
||||
|
@ -34,10 +34,14 @@ export class PositionNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
public setViewport(user: UserInterface, viewport: ViewportInterface): void {
|
||||
/**
|
||||
* Sets the viewport coordinates.
|
||||
* Returns the list of new users to add
|
||||
*/
|
||||
public setViewport(user: UserInterface, viewport: ViewportInterface): UserInterface[] {
|
||||
if (viewport.left > viewport.right || viewport.top > viewport.bottom) {
|
||||
console.warn('Invalid viewport received: ', viewport);
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
const oldZones = user.listenedZones;
|
||||
@ -55,12 +59,17 @@ export class PositionNotifier {
|
||||
const addedZones = [...newZones].filter(x => !oldZones.has(x));
|
||||
const removedZones = [...oldZones].filter(x => !newZones.has(x));
|
||||
|
||||
|
||||
let users: UserInterface[] = [];
|
||||
for (const zone of addedZones) {
|
||||
zone.startListening(user);
|
||||
users = users.concat(Array.from(zone.getPlayers()))
|
||||
}
|
||||
for (const zone of removedZones) {
|
||||
zone.stopListening(user);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public updatePosition(user: UserInterface, userPosition: PointInterface): void {
|
||||
@ -87,6 +96,11 @@ export class PositionNotifier {
|
||||
const oldZoneDesc = this.getZoneDescriptorFromCoordinates(user.position.x, user.position.y);
|
||||
const oldZone = this.getZone(oldZoneDesc.i, oldZoneDesc.j);
|
||||
oldZone.leave(user, null);
|
||||
|
||||
// Also, let's stop listening on viewports
|
||||
for (const zone of user.listenedZones) {
|
||||
zone.stopListening(user);
|
||||
}
|
||||
}
|
||||
|
||||
private getZone(i: number, j: number): Zone {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
import {isPointInterface} from "./PointInterface";
|
||||
import {isViewport} from "./ViewportMessage";
|
||||
|
||||
export const isJoinRoomMessageInterface =
|
||||
new tg.IsInterface().withProperties({
|
||||
roomId: tg.isString,
|
||||
position: isPointInterface,
|
||||
viewport: isViewport
|
||||
}).get();
|
||||
export type JoinRoomMessageInterface = tg.GuardedType<typeof isJoinRoomMessageInterface>;
|
||||
|
@ -6,7 +6,9 @@ import {UserInterface} from "./UserInterface";
|
||||
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||
import {PositionInterface} from "_Model/PositionInterface";
|
||||
import {Identificable} from "_Model/Websocket/Identificable";
|
||||
import {Zone} from "_Model/Zone";
|
||||
import {UserEntersCallback, UserLeavesCallback, UserMovesCallback, Zone} from "_Model/Zone";
|
||||
import {PositionNotifier} from "./PositionNotifier";
|
||||
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||
|
||||
export type ConnectCallback = (user: string, group: Group) => void;
|
||||
export type DisconnectCallback = (user: string, group: Group) => void;
|
||||
@ -28,12 +30,17 @@ export class World {
|
||||
private readonly groupUpdatedCallback: GroupUpdatedCallback;
|
||||
private readonly groupDeletedCallback: GroupDeletedCallback;
|
||||
|
||||
private readonly positionNotifier: PositionNotifier;
|
||||
|
||||
constructor(connectCallback: ConnectCallback,
|
||||
disconnectCallback: DisconnectCallback,
|
||||
minDistance: number,
|
||||
groupRadius: number,
|
||||
groupUpdatedCallback: GroupUpdatedCallback,
|
||||
groupDeletedCallback: GroupDeletedCallback)
|
||||
groupDeletedCallback: GroupDeletedCallback,
|
||||
onUserEnters: UserEntersCallback,
|
||||
onUserMoves: UserMovesCallback,
|
||||
onUserLeaves: UserLeavesCallback)
|
||||
{
|
||||
this.users = new Map<string, UserInterface>();
|
||||
this.groups = new Set<Group>();
|
||||
@ -43,6 +50,8 @@ export class World {
|
||||
this.groupRadius = groupRadius;
|
||||
this.groupUpdatedCallback = groupUpdatedCallback;
|
||||
this.groupDeletedCallback = groupDeletedCallback;
|
||||
// A zone is 10 sprites wide.
|
||||
this.positionNotifier = new PositionNotifier(320, 320, onUserEnters, onUserMoves, onUserLeaves);
|
||||
}
|
||||
|
||||
public getGroups(): Group[] {
|
||||
@ -73,6 +82,10 @@ export class World {
|
||||
this.leaveGroup(userObj);
|
||||
}
|
||||
this.users.delete(user.userId);
|
||||
|
||||
if (userObj !== undefined) {
|
||||
this.positionNotifier.leave(userObj);
|
||||
}
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
@ -85,6 +98,8 @@ export class World {
|
||||
return;
|
||||
}
|
||||
|
||||
this.positionNotifier.updatePosition(user, userPosition);
|
||||
|
||||
user.position = userPosition;
|
||||
|
||||
if (user.silent) {
|
||||
@ -318,4 +333,12 @@ export class World {
|
||||
}
|
||||
return 0;
|
||||
}*/
|
||||
setViewport(socket : Identificable, viewport: ViewportInterface): UserInterface[] {
|
||||
const user = this.users.get(socket.userId);
|
||||
if(typeof user === 'undefined') {
|
||||
console.warn('In setViewport, could not find user with ID "'+socket.userId+'" in world.');
|
||||
return [];
|
||||
}
|
||||
return this.positionNotifier.setViewport(user, viewport);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import {UserInterface} from "./UserInterface";
|
||||
import {PointInterface} from "_Model/Websocket/PointInterface";
|
||||
import {PositionInterface} from "_Model/PositionInterface";
|
||||
|
||||
export type UserEntersCallback = (user: UserInterface) => void;
|
||||
export type UserMovesCallback = (user: UserInterface, position: PointInterface) => void;
|
||||
export type UserLeavesCallback = (user: UserInterface) => void;
|
||||
export type UserEntersCallback = (user: UserInterface, listener: UserInterface) => void;
|
||||
export type UserMovesCallback = (user: UserInterface, position: PointInterface, listener: UserInterface) => void;
|
||||
export type UserLeavesCallback = (user: UserInterface, listener: UserInterface) => void;
|
||||
|
||||
export class Zone {
|
||||
private players: Set<UserInterface> = new Set<UserInterface>();
|
||||
@ -27,7 +27,7 @@ export class Zone {
|
||||
private notifyUserLeft(user: UserInterface, newZone: Zone|null) {
|
||||
for (const listener of this.listeners) {
|
||||
if (listener !== user && (newZone === null || !listener.listenedZones.has(newZone))) {
|
||||
this.onUserLeaves(user);
|
||||
this.onUserLeaves(user, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,40 +46,51 @@ export class Zone {
|
||||
continue;
|
||||
}
|
||||
if (oldZone === null || !listener.listenedZones.has(oldZone)) {
|
||||
this.onUserEnters(user);
|
||||
this.onUserEnters(user, listener);
|
||||
} else {
|
||||
this.onUserMoves(user, position);
|
||||
this.onUserMoves(user, position, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public move(user: UserInterface, position: PointInterface) {
|
||||
if (!this.players.has(user)) {
|
||||
this.players.add(user);
|
||||
const foo = this.players;
|
||||
this.notifyUserEnter(user, null, position);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const listener of this.listeners) {
|
||||
if (listener !== user) {
|
||||
this.onUserMoves(user,position);
|
||||
this.onUserMoves(user,position, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public startListening(user: UserInterface): void {
|
||||
public startListening(listener: UserInterface): void {
|
||||
for (const player of this.players) {
|
||||
if (player !== user) {
|
||||
this.onUserEnters(user);
|
||||
if (player !== listener) {
|
||||
this.onUserEnters(player, listener);
|
||||
}
|
||||
}
|
||||
|
||||
this.listeners.add(user);
|
||||
user.listenedZones.add(this);
|
||||
this.listeners.add(listener);
|
||||
listener.listenedZones.add(this);
|
||||
}
|
||||
|
||||
public stopListening(user: UserInterface): void {
|
||||
public stopListening(listener: UserInterface): void {
|
||||
for (const player of this.players) {
|
||||
if (player !== user) {
|
||||
this.onUserLeaves(user);
|
||||
if (player !== listener) {
|
||||
this.onUserLeaves(player, listener);
|
||||
}
|
||||
}
|
||||
|
||||
this.listeners.delete(user);
|
||||
user.listenedZones.delete(this);
|
||||
this.listeners.delete(listener);
|
||||
listener.listenedZones.delete(this);
|
||||
}
|
||||
|
||||
public getPlayers(): Set<UserInterface> {
|
||||
return this.players;
|
||||
}
|
||||
}
|
||||
|
@ -139,13 +139,15 @@ describe("PositionNotifier", () => {
|
||||
listenedZones: new Set<Zone>(),
|
||||
} as UserInterface;
|
||||
|
||||
positionNotifier.setViewport(user1, {
|
||||
let newUsers = positionNotifier.setViewport(user1, {
|
||||
left: 200,
|
||||
right: 600,
|
||||
top: 100,
|
||||
bottom: 500
|
||||
});
|
||||
|
||||
expect(newUsers.length).toBe(0);
|
||||
|
||||
move(user2, 500, 500, positionNotifier);
|
||||
|
||||
expect(enterTriggered).toBe(true);
|
||||
@ -178,7 +180,7 @@ describe("PositionNotifier", () => {
|
||||
leaveTriggered = false;
|
||||
|
||||
// Move the viewport back on the user.
|
||||
positionNotifier.setViewport(user1, {
|
||||
newUsers = positionNotifier.setViewport(user1, {
|
||||
left: 200,
|
||||
right: 600,
|
||||
top: 100,
|
||||
@ -189,5 +191,6 @@ describe("PositionNotifier", () => {
|
||||
expect(moveTriggered).toBe(false);
|
||||
expect(leaveTriggered).toBe(false);
|
||||
enterTriggered = false;
|
||||
expect(newUsers.length).toBe(1);
|
||||
});
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ describe("World", () => {
|
||||
|
||||
}
|
||||
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {});
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {}, () => {}, () => {});
|
||||
|
||||
world.join({ userId: "foo" }, new Point(100, 100));
|
||||
|
||||
@ -40,7 +40,7 @@ describe("World", () => {
|
||||
|
||||
}
|
||||
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {});
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {}, () => {}, () => {});
|
||||
|
||||
world.join({ userId: "foo" }, new Point(100, 100));
|
||||
|
||||
@ -69,7 +69,7 @@ describe("World", () => {
|
||||
disconnectCallNumber++;
|
||||
}
|
||||
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {});
|
||||
const world = new World(connect, disconnect, 160, 160, () => {}, () => {}, () => {}, () => {}, () => {});
|
||||
|
||||
world.join({ userId: "foo" }, new Point(100, 100));
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
|
@ -182,9 +182,13 @@ export class Connection implements Connection {
|
||||
}
|
||||
|
||||
|
||||
public joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean): Promise<MessageUserPositionInterface[]> {
|
||||
public joinARoom(roomId: string, startX: number, startY: number, direction: string, moving: boolean, viewport: ViewportInterface): Promise<MessageUserPositionInterface[]> {
|
||||
const promise = new Promise<MessageUserPositionInterface[]>((resolve, reject) => {
|
||||
this.socket.emit(EventMessage.JOIN_ROOM, { roomId, position: {x: startX, y: startY, direction, moving }}, (userPositions: MessageUserPositionInterface[]) => {
|
||||
this.socket.emit(EventMessage.JOIN_ROOM, {
|
||||
roomId,
|
||||
position: {x: startX, y: startY, direction, moving },
|
||||
viewport,
|
||||
}, (userPositions: MessageUserPositionInterface[]) => {
|
||||
resolve(userPositions);
|
||||
});
|
||||
})
|
||||
@ -203,6 +207,10 @@ export class Connection implements Connection {
|
||||
this.socket.emit(EventMessage.SET_SILENT, silent);
|
||||
}
|
||||
|
||||
public setViewport(viewport: ViewportInterface): void {
|
||||
this.socket.emit(EventMessage.SET_VIEWPORT, viewport);
|
||||
}
|
||||
|
||||
public onUserJoins(callback: (message: MessageUserJoined) => void): void {
|
||||
this.socket.on(EventMessage.JOIN_ROOM, callback);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
private startLayerName: string|undefined;
|
||||
private presentationModeSprite!: Sprite;
|
||||
private chatModeSprite!: Sprite;
|
||||
private repositionCallback!: (this: Window, ev: UIEvent) => void;
|
||||
private onResizeCallback!: (this: Window, ev: UIEvent) => void;
|
||||
private gameMap!: GameMap;
|
||||
|
||||
static createFromUrl(mapUrlFile: string, instance: string, key: string|null = null): GameScene {
|
||||
@ -226,7 +226,7 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
|
||||
this.scene.stop(this.scene.key);
|
||||
this.scene.remove(this.scene.key);
|
||||
window.removeEventListener('resize', this.repositionCallback);
|
||||
window.removeEventListener('resize', this.onResizeCallback);
|
||||
})
|
||||
|
||||
// When connection is performed, let's connect SimplePeer
|
||||
@ -412,8 +412,8 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
this.switchLayoutMode();
|
||||
});
|
||||
|
||||
this.repositionCallback = this.reposition.bind(this);
|
||||
window.addEventListener('resize', this.repositionCallback);
|
||||
this.onResizeCallback = this.onResize.bind(this);
|
||||
window.addEventListener('resize', this.onResizeCallback);
|
||||
this.reposition();
|
||||
|
||||
// From now, this game scene will be notified of reposition events
|
||||
@ -636,7 +636,17 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
|
||||
//join room
|
||||
this.connectionPromise.then((connection: Connection) => {
|
||||
connection.joinARoom(this.RoomId, this.startX, this.startY, PlayerAnimationNames.WalkDown, false).then((userPositions: MessageUserPositionInterface[]) => {
|
||||
const camera = this.cameras.main;
|
||||
connection.joinARoom(this.RoomId,
|
||||
this.startX,
|
||||
this.startY,
|
||||
PlayerAnimationNames.WalkDown,
|
||||
false, {
|
||||
left: camera.scrollX,
|
||||
top: camera.scrollY,
|
||||
right: camera.scrollX + camera.width,
|
||||
bottom: camera.scrollY + camera.height,
|
||||
}).then((userPositions: MessageUserPositionInterface[]) => {
|
||||
this.initUsersPosition(userPositions);
|
||||
});
|
||||
|
||||
@ -747,7 +757,7 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
this.simplePeer.unregister();
|
||||
this.scene.stop();
|
||||
this.scene.remove(this.scene.key);
|
||||
window.removeEventListener('resize', this.repositionCallback);
|
||||
window.removeEventListener('resize', this.onResizeCallback);
|
||||
this.scene.start(nextSceneKey.key, {
|
||||
startLayerName: nextSceneKey.hash
|
||||
});
|
||||
@ -936,6 +946,19 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
||||
return mapUrlStart.substring(startPos, endPos);
|
||||
}
|
||||
|
||||
private onResize(): void {
|
||||
this.reposition();
|
||||
|
||||
// Send new viewport to server
|
||||
const camera = this.cameras.main;
|
||||
this.connection.setViewport({
|
||||
left: camera.scrollX,
|
||||
top: camera.scrollY,
|
||||
right: camera.scrollX + camera.width,
|
||||
bottom: camera.scrollY + camera.height,
|
||||
});
|
||||
}
|
||||
|
||||
private reposition(): void {
|
||||
this.presentationModeSprite.setY(this.game.renderer.height - 2);
|
||||
this.chatModeSprite.setY(this.game.renderer.height - 2);
|
||||
|
Loading…
Reference in New Issue
Block a user