Plugin PositionNotifier into the main application.

This commit is contained in:
David Négrier 2020-09-15 16:21:41 +02:00
parent f8d462b0d7
commit d24ec0bd75
10 changed files with 170 additions and 62 deletions

View file

@ -20,6 +20,7 @@ import {isWebRtcSignalMessageInterface} from "../Model/Websocket/WebRtcSignalMes
import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface"; import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface";
import {uuid} from 'uuidv4'; import {uuid} from 'uuidv4';
import {isUserMovesInterface} from "../Model/Websocket/UserMovesMessage"; import {isUserMovesInterface} from "../Model/Websocket/UserMovesMessage";
import {isViewport} from "../Model/Websocket/ViewportMessage";
enum SockerIoEvent { enum SockerIoEvent {
CONNECTION = "connection", CONNECTION = "connection",
@ -212,22 +213,16 @@ export class IoSocketController {
//join new previous room //join new previous room
const world = this.joinRoom(Client, roomId, message.position); const world = this.joinRoom(Client, roomId, message.position);
//add function to refresh position user in real time. const users = world.setViewport(Client, message.viewport);
//this.refreshUserPosition(Client); const listOfUsers = users.map((user: UserInterface) => {
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 player: ExSocketInterface|undefined = this.sockets.get(user.id); const player: ExSocketInterface|undefined = this.sockets.get(user.id);
if (player === undefined) { 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!"); 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.characterLayers, player.position); return new MessageUserPosition(user.id, player.name, player.characterLayers, player.position);
}).filter((item: MessageUserPosition|null) => item !== null); }, users);
answerFn(listOfUsers); answerFn(listOfUsers);
} catch (e) { } catch (e) {
console.error('An error occurred on "join_room" event'); 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 => { socket.on(SockerIoEvent.USER_POSITION, (userMovesMessage: unknown): void => {
console.log(SockerIoEvent.USER_POSITION, userMovesMessage); console.log(SockerIoEvent.USER_POSITION, userMovesMessage);
try { try {
@ -257,19 +276,7 @@ export class IoSocketController {
return; return;
} }
world.updatePosition(Client, Client.position); world.updatePosition(Client, Client.position);
world.setViewport(Client, Client.viewport);
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));
} catch (e) { } catch (e) {
console.error('An error occurred on "user_position" event'); console.error('An error occurred on "user_position" event');
console.error(e); console.error(e);
@ -404,8 +411,6 @@ export class IoSocketController {
// leave previous room and world // leave previous room and world
if(Client.roomId){ if(Client.roomId){
try { try {
Client.to(Client.roomId).emit(SockerIoEvent.USER_LEFT, Client.userId);
//user leave previous world //user leave previous world
const world: World | undefined = this.Worlds.get(Client.roomId); const world: World | undefined = this.Worlds.get(Client.roomId);
if (world) { if (world) {
@ -441,6 +446,25 @@ export class IoSocketController {
this.sendUpdateGroupEvent(group); this.sendUpdateGroupEvent(group);
}, (groupUuid: string, lastUser: UserInterface) => { }, (groupUuid: string, lastUser: UserInterface) => {
this.sendDeleteGroupEvent(groupUuid, lastUser); 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); this.Worlds.set(roomId, world);
} }

View file

@ -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) { if (viewport.left > viewport.right || viewport.top > viewport.bottom) {
console.warn('Invalid viewport received: ', viewport); console.warn('Invalid viewport received: ', viewport);
return; return [];
} }
const oldZones = user.listenedZones; const oldZones = user.listenedZones;
@ -55,12 +59,17 @@ export class PositionNotifier {
const addedZones = [...newZones].filter(x => !oldZones.has(x)); const addedZones = [...newZones].filter(x => !oldZones.has(x));
const removedZones = [...oldZones].filter(x => !newZones.has(x)); const removedZones = [...oldZones].filter(x => !newZones.has(x));
let users: UserInterface[] = [];
for (const zone of addedZones) { for (const zone of addedZones) {
zone.startListening(user); zone.startListening(user);
users = users.concat(Array.from(zone.getPlayers()))
} }
for (const zone of removedZones) { for (const zone of removedZones) {
zone.stopListening(user); zone.stopListening(user);
} }
return users;
} }
public updatePosition(user: UserInterface, userPosition: PointInterface): void { 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 oldZoneDesc = this.getZoneDescriptorFromCoordinates(user.position.x, user.position.y);
const oldZone = this.getZone(oldZoneDesc.i, oldZoneDesc.j); const oldZone = this.getZone(oldZoneDesc.i, oldZoneDesc.j);
oldZone.leave(user, null); 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 { private getZone(i: number, j: number): Zone {

View file

@ -1,9 +1,11 @@
import * as tg from "generic-type-guard"; import * as tg from "generic-type-guard";
import {isPointInterface} from "./PointInterface"; import {isPointInterface} from "./PointInterface";
import {isViewport} from "./ViewportMessage";
export const isJoinRoomMessageInterface = export const isJoinRoomMessageInterface =
new tg.IsInterface().withProperties({ new tg.IsInterface().withProperties({
roomId: tg.isString, roomId: tg.isString,
position: isPointInterface, position: isPointInterface,
viewport: isViewport
}).get(); }).get();
export type JoinRoomMessageInterface = tg.GuardedType<typeof isJoinRoomMessageInterface>; export type JoinRoomMessageInterface = tg.GuardedType<typeof isJoinRoomMessageInterface>;

View file

@ -6,7 +6,9 @@ import {UserInterface} from "./UserInterface";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
import {PositionInterface} from "_Model/PositionInterface"; import {PositionInterface} from "_Model/PositionInterface";
import {Identificable} from "_Model/Websocket/Identificable"; 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 ConnectCallback = (user: string, group: Group) => void;
export type DisconnectCallback = (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 groupUpdatedCallback: GroupUpdatedCallback;
private readonly groupDeletedCallback: GroupDeletedCallback; private readonly groupDeletedCallback: GroupDeletedCallback;
private readonly positionNotifier: PositionNotifier;
constructor(connectCallback: ConnectCallback, constructor(connectCallback: ConnectCallback,
disconnectCallback: DisconnectCallback, disconnectCallback: DisconnectCallback,
minDistance: number, minDistance: number,
groupRadius: number, groupRadius: number,
groupUpdatedCallback: GroupUpdatedCallback, groupUpdatedCallback: GroupUpdatedCallback,
groupDeletedCallback: GroupDeletedCallback) groupDeletedCallback: GroupDeletedCallback,
onUserEnters: UserEntersCallback,
onUserMoves: UserMovesCallback,
onUserLeaves: UserLeavesCallback)
{ {
this.users = new Map<string, UserInterface>(); this.users = new Map<string, UserInterface>();
this.groups = new Set<Group>(); this.groups = new Set<Group>();
@ -43,6 +50,8 @@ export class World {
this.groupRadius = groupRadius; this.groupRadius = groupRadius;
this.groupUpdatedCallback = groupUpdatedCallback; this.groupUpdatedCallback = groupUpdatedCallback;
this.groupDeletedCallback = groupDeletedCallback; this.groupDeletedCallback = groupDeletedCallback;
// A zone is 10 sprites wide.
this.positionNotifier = new PositionNotifier(320, 320, onUserEnters, onUserMoves, onUserLeaves);
} }
public getGroups(): Group[] { public getGroups(): Group[] {
@ -73,6 +82,10 @@ export class World {
this.leaveGroup(userObj); this.leaveGroup(userObj);
} }
this.users.delete(user.userId); this.users.delete(user.userId);
if (userObj !== undefined) {
this.positionNotifier.leave(userObj);
}
} }
public isEmpty(): boolean { public isEmpty(): boolean {
@ -85,6 +98,8 @@ export class World {
return; return;
} }
this.positionNotifier.updatePosition(user, userPosition);
user.position = userPosition; user.position = userPosition;
if (user.silent) { if (user.silent) {
@ -318,4 +333,12 @@ export class World {
} }
return 0; 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);
}
} }

View file

@ -2,9 +2,9 @@ import {UserInterface} from "./UserInterface";
import {PointInterface} from "_Model/Websocket/PointInterface"; import {PointInterface} from "_Model/Websocket/PointInterface";
import {PositionInterface} from "_Model/PositionInterface"; import {PositionInterface} from "_Model/PositionInterface";
export type UserEntersCallback = (user: UserInterface) => void; export type UserEntersCallback = (user: UserInterface, listener: UserInterface) => void;
export type UserMovesCallback = (user: UserInterface, position: PointInterface) => void; export type UserMovesCallback = (user: UserInterface, position: PointInterface, listener: UserInterface) => void;
export type UserLeavesCallback = (user: UserInterface) => void; export type UserLeavesCallback = (user: UserInterface, listener: UserInterface) => void;
export class Zone { export class Zone {
private players: Set<UserInterface> = new Set<UserInterface>(); private players: Set<UserInterface> = new Set<UserInterface>();
@ -27,7 +27,7 @@ export class Zone {
private notifyUserLeft(user: UserInterface, newZone: Zone|null) { private notifyUserLeft(user: UserInterface, newZone: Zone|null) {
for (const listener of this.listeners) { for (const listener of this.listeners) {
if (listener !== user && (newZone === null || !listener.listenedZones.has(newZone))) { if (listener !== user && (newZone === null || !listener.listenedZones.has(newZone))) {
this.onUserLeaves(user); this.onUserLeaves(user, listener);
} }
} }
} }
@ -46,40 +46,51 @@ export class Zone {
continue; continue;
} }
if (oldZone === null || !listener.listenedZones.has(oldZone)) { if (oldZone === null || !listener.listenedZones.has(oldZone)) {
this.onUserEnters(user); this.onUserEnters(user, listener);
} else { } else {
this.onUserMoves(user, position); this.onUserMoves(user, position, listener);
} }
} }
} }
public move(user: UserInterface, position: PointInterface) { 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) { for (const listener of this.listeners) {
if (listener !== user) { 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) { for (const player of this.players) {
if (player !== user) { if (player !== listener) {
this.onUserEnters(user); this.onUserEnters(player, listener);
} }
} }
this.listeners.add(user); this.listeners.add(listener);
user.listenedZones.add(this); listener.listenedZones.add(this);
} }
public stopListening(user: UserInterface): void { public stopListening(listener: UserInterface): void {
for (const player of this.players) { for (const player of this.players) {
if (player !== user) { if (player !== listener) {
this.onUserLeaves(user); this.onUserLeaves(player, listener);
} }
} }
this.listeners.delete(user); this.listeners.delete(listener);
user.listenedZones.delete(this); listener.listenedZones.delete(this);
}
public getPlayers(): Set<UserInterface> {
return this.players;
} }
} }

View file

@ -139,13 +139,15 @@ describe("PositionNotifier", () => {
listenedZones: new Set<Zone>(), listenedZones: new Set<Zone>(),
} as UserInterface; } as UserInterface;
positionNotifier.setViewport(user1, { let newUsers = positionNotifier.setViewport(user1, {
left: 200, left: 200,
right: 600, right: 600,
top: 100, top: 100,
bottom: 500 bottom: 500
}); });
expect(newUsers.length).toBe(0);
move(user2, 500, 500, positionNotifier); move(user2, 500, 500, positionNotifier);
expect(enterTriggered).toBe(true); expect(enterTriggered).toBe(true);
@ -178,7 +180,7 @@ describe("PositionNotifier", () => {
leaveTriggered = false; leaveTriggered = false;
// Move the viewport back on the user. // Move the viewport back on the user.
positionNotifier.setViewport(user1, { newUsers = positionNotifier.setViewport(user1, {
left: 200, left: 200,
right: 600, right: 600,
top: 100, top: 100,
@ -189,5 +191,6 @@ describe("PositionNotifier", () => {
expect(moveTriggered).toBe(false); expect(moveTriggered).toBe(false);
expect(leaveTriggered).toBe(false); expect(leaveTriggered).toBe(false);
enterTriggered = false; enterTriggered = false;
expect(newUsers.length).toBe(1);
}); });
}) })

View file

@ -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)); 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)); world.join({ userId: "foo" }, new Point(100, 100));
@ -69,7 +69,7 @@ describe("World", () => {
disconnectCallNumber++; 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)); world.join({ userId: "foo" }, new Point(100, 100));

View file

@ -12,7 +12,7 @@
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each 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. */ // "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist", /* Redirect output structure to the directory. */ "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. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */

View file

@ -182,11 +182,15 @@ 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) => { 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, {
resolve(userPositions); roomId,
}); position: {x: startX, y: startY, direction, moving },
viewport,
}, (userPositions: MessageUserPositionInterface[]) => {
resolve(userPositions);
});
}) })
return promise; return promise;
} }
@ -203,6 +207,10 @@ export class Connection implements Connection {
this.socket.emit(EventMessage.SET_SILENT, silent); 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 { public onUserJoins(callback: (message: MessageUserJoined) => void): void {
this.socket.on(EventMessage.JOIN_ROOM, callback); this.socket.on(EventMessage.JOIN_ROOM, callback);
} }

View file

@ -111,7 +111,7 @@ export class GameScene extends Phaser.Scene implements CenterListener {
private startLayerName: string|undefined; private startLayerName: string|undefined;
private presentationModeSprite!: Sprite; private presentationModeSprite!: Sprite;
private chatModeSprite!: Sprite; private chatModeSprite!: Sprite;
private repositionCallback!: (this: Window, ev: UIEvent) => void; private onResizeCallback!: (this: Window, ev: UIEvent) => void;
private gameMap!: GameMap; private gameMap!: GameMap;
static createFromUrl(mapUrlFile: string, instance: string, key: string|null = null): GameScene { 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.stop(this.scene.key);
this.scene.remove(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 // When connection is performed, let's connect SimplePeer
@ -412,8 +412,8 @@ export class GameScene extends Phaser.Scene implements CenterListener {
this.switchLayoutMode(); this.switchLayoutMode();
}); });
this.repositionCallback = this.reposition.bind(this); this.onResizeCallback = this.onResize.bind(this);
window.addEventListener('resize', this.repositionCallback); window.addEventListener('resize', this.onResizeCallback);
this.reposition(); this.reposition();
// From now, this game scene will be notified of reposition events // 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 //join room
this.connectionPromise.then((connection: Connection) => { 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); this.initUsersPosition(userPositions);
}); });
@ -747,7 +757,7 @@ export class GameScene extends Phaser.Scene implements CenterListener {
this.simplePeer.unregister(); this.simplePeer.unregister();
this.scene.stop(); this.scene.stop();
this.scene.remove(this.scene.key); this.scene.remove(this.scene.key);
window.removeEventListener('resize', this.repositionCallback); window.removeEventListener('resize', this.onResizeCallback);
this.scene.start(nextSceneKey.key, { this.scene.start(nextSceneKey.key, {
startLayerName: nextSceneKey.hash startLayerName: nextSceneKey.hash
}); });
@ -936,6 +946,19 @@ export class GameScene extends Phaser.Scene implements CenterListener {
return mapUrlStart.substring(startPos, endPos); 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 { private reposition(): void {
this.presentationModeSprite.setY(this.game.renderer.height - 2); this.presentationModeSprite.setY(this.game.renderer.height - 2);
this.chatModeSprite.setY(this.game.renderer.height - 2); this.chatModeSprite.setY(this.game.renderer.height - 2);