diff options
Diffstat (limited to 'client')
20 files changed, 769 insertions, 376 deletions
diff --git a/client/src/akkamon/DataWrappers.ts b/client/src/akkamon/DataWrappers.ts index 6fff618..2c01f50 100644 --- a/client/src/akkamon/DataWrappers.ts +++ b/client/src/akkamon/DataWrappers.ts @@ -1,75 +1,90 @@ -export class Queue<T> { - private _data = new Array(); +export interface Queue<T> { + _data: T[] + push: (ele: T) => void + pushArray: (ele: T[]) => void + pop: () => T | undefined + isEmpty: () => boolean + peek: () => T | undefined +} - constructor(data?: Array<T>) { - if (data !== undefined) { - this._data = data; - } - } +export function baseQueue<T>(): Queue<T> { + return { + _data: <T[]> [], - push(element: T): void { - this._data.push(element); - } - - pushArray(arr: T[]): void { - for (var element of arr) { + push: function (element: T): void { this._data.push(element); - } - } + }, - pop(): T | undefined { - return this._data.shift(); - } + pushArray: function (arr: T[]) { + for (let ele of arr) { + this._data.push(ele); + } + }, - isEmpty(): boolean { - return this._data.length == 0; - } + pop: function (): T | undefined { + return this._data.shift(); + }, + + peek: function (): T | undefined { + return this._data[0]; + }, - peek() { - return this._data[0]; + + isEmpty: function (): boolean { + return this._data.length == 0; + }, } } -export class Stack<T> { - private _data = new Array(); +export function queueFromArray<T>(arr: T[]): Queue<T> { + let base: Queue<T> = baseQueue(); + base._data = arr; + return base; +} - constructor(data?: Array<T>) { - if (data !== undefined) { - this._data = data; - } - } +export interface Stack<T> { + _data: T[] + pop: () => T | undefined + peek: () => T | undefined + push: (element: T) => void + size: () => number + isEmpty: () => boolean + clear: () => void + cloneData: () => T[] - pop(): T | undefined { - return this._data.pop(); - } +} - push(element: T): void { - this._data.push(element); - } +export function baseStack<T>(): Stack<T> { + return { + _data: <T[]> [], - peek() { - if (this.length === 0) { - return undefined; - } else { - return this._data[this.length - 1]; - } - } + size: function (): number { + return this._data.length; + }, - get length() { - return this._data.length; - } + pop: function (): T | undefined { + return this._data.pop(); + }, - isEmpty() { - return this.length === 0; - } + peek: function (): T | undefined { + return this._data[this.size() - 1]; + }, - clear() { - this._data = new Array(); - } + push: function (ele: T): void { + this._data.push(ele); + }, - cloneData() { - return new Array(this._data); - } + isEmpty: function (): boolean { + return this.size() == 0; + }, + clear: function (): void { + this._data = []; + }, + + cloneData: function (): T[] { + return [... this._data]; + } + } } diff --git a/client/src/akkamon/GameConfig.ts b/client/src/akkamon/GameConfig.ts index 53a10a2..a0abf11 100644 --- a/client/src/akkamon/GameConfig.ts +++ b/client/src/akkamon/GameConfig.ts @@ -1,9 +1,5 @@ -import { - DemoScene -} from './scenes/DemoScene'; -import { - BootScene -} from './scenes/BootScene'; +import DemoScene from './scenes/DemoScene'; +import BootScene from './scenes/BootScene'; export const gameConfig: Phaser.Types.Core.GameConfig & Phaser.Types.Core.RenderConfig = { diff --git a/client/src/akkamon/PhaserTypes.ts b/client/src/akkamon/PhaserTypes.ts new file mode 100644 index 0000000..4725a31 --- /dev/null +++ b/client/src/akkamon/PhaserTypes.ts @@ -0,0 +1,3 @@ +// type Constructor = new (...args: any[]) => {}; +type GConstructor<T = {}> = new (...args: any[]) => T; +export type BasePhaserScene = GConstructor<Phaser.Scene> diff --git a/client/src/akkamon/client/Client.ts b/client/src/akkamon/client/Client.ts index 477ff46..2cc5ee8 100644 --- a/client/src/akkamon/client/Client.ts +++ b/client/src/akkamon/client/Client.ts @@ -14,33 +14,39 @@ import { InteractionEngine } from './InteractionEngine'; import type { AkkamonClient } from './AkkamonClient'; -import type { AkkamonWorldScene } from '../scenes/AkkamonWorldScene'; +import type { WorldScene } from '../scenes/WorldScene'; import { DirectionToAnimation } from '../render/DirectionToAnimation'; import { Direction } from '../render/Direction'; -import { - EventType, - HeartBeatReplyEvent, - IncomingEvent, - AkkamonEvent, - InteractionRequestEvent, - Interaction -} from './Events'; - function delay(ms: number) { return new Promise(resolve => { setTimeout(resolve, ms); }); } +import { + EventType, + AkkamonEvent +} from './EventType' + +import type { + IncomingEvent, +} from './IncomingEvents'; + +import { + HeartBeatReplyEvent, + Interaction, + OutgoingInteractionRequestEvent +} from './OutgoingEvents'; + export class Client implements AkkamonClient { private session: AkkamonSession; - private scene?: AkkamonWorldScene; + private scene?: WorldScene; private gridPhysics?: GridPhysics; private controls?: GridControls | UIControls; @@ -67,6 +73,7 @@ export class Client implements AkkamonClient in(eventString: string) { let event: IncomingEvent = JSON.parse(eventString); + // this[event.type](event); // console.log(event); switch (event.type) { case EventType.HEART_BEAT: @@ -81,12 +88,14 @@ export class Client implements AkkamonClient this.session.trainerId = event.trainerId; } break; - case EventType.INTERACTION_REPLY: - console.log("Received an interaction reply!"); + case EventType.INTERACTION_REQUEST: + console.log("Received an interaction request!"); console.log(event); + // this.interactionEngine!.push(event); break; default: console.log("ignored incoming event, doesn't match EventType interface."); + console.log(event.type); break; } } @@ -117,8 +126,8 @@ export class Client implements AkkamonClient this.controls = new GridControls(this.scene!.input, this.gridPhysics!); } - requestInitPlayerSprite( - scene: AkkamonWorldScene + requestInitWorldScene( + scene: WorldScene ): void { this.scene = scene; @@ -152,7 +161,7 @@ export class Client implements AkkamonClient } private initAnimation( - scene: AkkamonWorldScene, + scene: WorldScene, player: PlayerSprite ): void { @@ -168,7 +177,7 @@ export class Client implements AkkamonClient camera.setBounds(0, 0, scene.map!.widthInPixels, scene.map!.heightInPixels); } - private createPlayerAnimation(scene: AkkamonWorldScene, direction: Direction, start: number, end: number) { + private createPlayerAnimation(scene: WorldScene, direction: Direction, start: number, end: number) { let characterAnimations = DirectionToAnimation.directionToAnimation['misa']; scene.anims.create({ @@ -196,7 +205,7 @@ export class Client implements AkkamonClient console.log(this.getCurrentSceneKey()); console.log(JSON.stringify(interaction)); this.interactionEngine!.setAwaitingResponse(); - this.send(new InteractionRequestEvent( + this.send(new OutgoingInteractionRequestEvent( this.getCurrentSceneKey(), interaction )); diff --git a/client/src/akkamon/client/EventType.ts b/client/src/akkamon/client/EventType.ts new file mode 100644 index 0000000..7d6d483 --- /dev/null +++ b/client/src/akkamon/client/EventType.ts @@ -0,0 +1,16 @@ +export interface AkkamonEvent { + type: EventType +} + +export enum EventType { + HEART_BEAT = "HeartBeat", + TRAINER_REGISTRATION_REQUEST = "TrainerRegistrationRequestEvent", + TRAINER_REGISTRATION_REPLY = "TrainerRegistrationReplyEvent", + START_MOVING = "StartMoving", + STOP_MOVING = "StopMoving", + NEW_TILE_POS = "NewTilePos", + INTERACTION_REQUEST = "InteractionRequestEvent", + INTERACTION_REPLY = "InteractionReplyEvent", + INTERACTION_ABORTED = "InteractionAbortedEvent" +} + diff --git a/client/src/akkamon/client/Events.ts b/client/src/akkamon/client/Events.ts index d6319be..c437822 100644 --- a/client/src/akkamon/client/Events.ts +++ b/client/src/akkamon/client/Events.ts @@ -1,70 +1,9 @@ import Phaser from 'phaser'; import type { Direction } from '../render/Direction'; -export type TrainerPosition = { x: number, y: number } - -export type RemoteMovementQueues = { - [trainerId: string]: { value: Array<Direction> } -} - -export type Interaction = { - type: string, - requestingTrainerId: string, - receivingTrainerIds: string[] -} - - -export enum EventType { - HEART_BEAT = "HeartBeat", - TRAINER_REGISTRATION_REQUEST = "TrainerRegistrationRequestEvent", - TRAINER_REGISTRATION_REPLY = "TrainerRegistrationReplyEvent", - START_MOVING = "StartMoving", - STOP_MOVING = "StopMoving", - NEW_TILE_POS = "NewTilePos", - INTERACTION_REQUEST = "InteractionRequestEvent", - INTERACTION_REPLY = "InteractionReplyEvent", - INTERACTION_ABORTED = "InteractionAbortedEvent" -} - -export interface AkkamonEvent { - type: EventType -} - -export interface InteractionEvent extends AkkamonEvent { - interaction: Interaction -} - -export interface IncomingEvent extends AkkamonEvent { - remoteMovementQueues?: RemoteMovementQueues - trainerId?: string -} +import { EventType, AkkamonEvent } from './EventType'; // INCOMING EVENTS -export class HeartBeatReplyEvent implements IncomingEvent { - - public type: EventType = EventType.HEART_BEAT; - - constructor( - ) { } -} - -export class PlayerRegistrationReplyEvent implements IncomingEvent { - - public type: EventType = EventType.TRAINER_REGISTRATION_REPLY; - - constructor( - public trainerId: string - ) { } -} - -// export class InitBattleReplyEvent implements IncomingEvent { -// -// public type: EventType = EventType.INIT_BATTLE_REPLY; -// -// constructor( -// ) { } -// } - // OUTGOING EVENTS export class PlayerRegistrationRequestEvent implements AkkamonEvent { @@ -75,44 +14,3 @@ export class PlayerRegistrationRequestEvent implements AkkamonEvent { } -export class StartMovingEvent implements AkkamonEvent { - - public type: EventType = EventType.START_MOVING; - - constructor( - public sceneId: string, - public direction: Direction, - ) { } -} - -export class StopMovingEvent implements AkkamonEvent { - - public type: EventType = EventType.STOP_MOVING; - - constructor( - public sceneId: string, - public direction: Direction, - ) { } -} - -export class NewTilePosEvent implements AkkamonEvent { - - public type: EventType = EventType.NEW_TILE_POS; - - constructor( - public sceneId: string, - public tilePos: {x: number, y: number} - ) { } -} - - - -export class InteractionRequestEvent implements InteractionEvent { - - public type: EventType = EventType.INTERACTION_REQUEST; - - constructor( - public sceneId: string, - public interaction: Interaction, - ) { } -} diff --git a/client/src/akkamon/client/IncomingEvents.ts b/client/src/akkamon/client/IncomingEvents.ts new file mode 100644 index 0000000..0674c1c --- /dev/null +++ b/client/src/akkamon/client/IncomingEvents.ts @@ -0,0 +1,47 @@ +import { EventType, AkkamonEvent } from './EventType'; +import type { Direction } from '../render/Direction'; + + + +export interface IncomingEvent extends AkkamonEvent { + remoteMovementQueues?:{[trainerId: string]: { value: Array<Direction> }} + trainerId?: string + requestId?: number +} + +export class IncomingInteractionRequest implements IncomingEvent { + + public type: EventType = EventType.INTERACTION_REQUEST; + + constructor( + public interactionType: string, + public trainerId: string, + public requestName: string + ) { } +} + +export class HeartBeat implements IncomingEvent { + + public type: EventType = EventType.HEART_BEAT; + + constructor( + ) { } +} + +export class PlayerRegistrationReplyEvent implements IncomingEvent { + + public type: EventType = EventType.TRAINER_REGISTRATION_REPLY; + + constructor( + public trainerId: string + ) { } +} + +// export class InitBattleReplyEvent implements IncomingEvent { +// +// public type: EventType = EventType.INIT_BATTLE_REPLY; +// +// constructor( +// ) { } +// } + diff --git a/client/src/akkamon/client/InteractionEngine.ts b/client/src/akkamon/client/InteractionEngine.ts index 5746b73..92b6b81 100644 --- a/client/src/akkamon/client/InteractionEngine.ts +++ b/client/src/akkamon/client/InteractionEngine.ts @@ -1,9 +1,19 @@ import { AkkamonEngine } from '../render/engine/AkkamonEngine'; -import type { AkkamonWorldScene } from '../scenes/AkkamonWorldScene'; +import type { WorldScene } from '../scenes/WorldScene'; + +import { baseQueue } from '../DataWrappers'; + +import type { + IncomingInteractionRequest +} from './IncomingEvents'; + export class InteractionEngine extends AkkamonEngine { - constructor(scene: AkkamonWorldScene) { + + private messageQueue = baseQueue(); + + constructor(scene: WorldScene) { super(); } @@ -12,4 +22,7 @@ export class InteractionEngine extends AkkamonEngine { setAwaitingResponse() { } + + push() { + } } diff --git a/client/src/akkamon/client/OutgoingEvents.ts b/client/src/akkamon/client/OutgoingEvents.ts new file mode 100644 index 0000000..90b72c6 --- /dev/null +++ b/client/src/akkamon/client/OutgoingEvents.ts @@ -0,0 +1,78 @@ +import type { Direction } from '../render/Direction'; + +import { EventType, AkkamonEvent } from './EventType'; + +export type RemoteMovementQueues = { + [trainerId: string]: { value: Array<Direction> } +} + +export type Interaction = { + type: string, + requestingTrainerId: string, + receivingTrainerIds: string[] +} + +export interface InteractionEvent extends AkkamonEvent { + interaction: Interaction +} + +export class HeartBeatReplyEvent implements AkkamonEvent { + + public type: EventType = EventType.HEART_BEAT; + + constructor( + ) { } +} + + +export class PlayerRegistrationRequestEvent implements AkkamonEvent { + + public type: EventType = EventType.TRAINER_REGISTRATION_REQUEST; + + constructor( + ) { } +} + + +export class StartMovingEvent implements AkkamonEvent { + + public type: EventType = EventType.START_MOVING; + + constructor( + public sceneId: string, + public direction: Direction, + ) { } +} + +export class StopMovingEvent implements AkkamonEvent { + + public type: EventType = EventType.STOP_MOVING; + + constructor( + public sceneId: string, + public direction: Direction, + ) { } +} + +export class NewTilePosEvent implements AkkamonEvent { + + public type: EventType = EventType.NEW_TILE_POS; + + constructor( + public sceneId: string, + public tilePos: {x: number, y: number} + ) { } +} + + + +export class OutgoingInteractionRequestEvent implements InteractionEvent { + + public type: EventType = EventType.INTERACTION_REQUEST; + + constructor( + public sceneId: string, + public interaction: Interaction, + ) { } +} + diff --git a/client/src/akkamon/render/engine/GridPhysics.ts b/client/src/akkamon/render/engine/GridPhysics.ts index 04ff865..7c266bf 100644 --- a/client/src/akkamon/render/engine/GridPhysics.ts +++ b/client/src/akkamon/render/engine/GridPhysics.ts @@ -1,6 +1,6 @@ import Phaser from 'phaser'; -import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import { TILE_SIZE } from '../../scenes/WorldScene'; import { AkkamonEngine } from './AkkamonEngine'; @@ -12,7 +12,7 @@ import { StartMovingEvent, StopMovingEvent, NewTilePosEvent -} from '../../client/Events'; +} from '../../client/OutgoingEvents'; export class GridPhysics extends AkkamonEngine { @@ -26,7 +26,7 @@ export class GridPhysics extends AkkamonEngine { } private movementDirection: Direction = Direction.NONE; - private readonly speedPixelsPerSecond: number = AkkamonWorldScene.TILE_SIZE * 4; + private readonly speedPixelsPerSecond: number = TILE_SIZE * 4; private tileSizePixelsWalked: number = 0; @@ -90,7 +90,7 @@ export class GridPhysics extends AkkamonEngine { this.spriteMovement(pixelsToWalkThisUpdate); this.updatePlayerSpriteTilePosition(); } else { - this.spriteMovement(AkkamonWorldScene.TILE_SIZE - this.tileSizePixelsWalked); + this.spriteMovement(TILE_SIZE - this.tileSizePixelsWalked); this.stopMoving(); } } @@ -120,7 +120,7 @@ export class GridPhysics extends AkkamonEngine { private spriteMovement(pixelsToMove: number) { this.tileSizePixelsWalked += pixelsToMove; - this.tileSizePixelsWalked %= AkkamonWorldScene.TILE_SIZE; + this.tileSizePixelsWalked %= TILE_SIZE; const directionVec = GridPhysics.movementDirectionVectors[ @@ -139,7 +139,7 @@ export class GridPhysics extends AkkamonEngine { pixelsToWalkThisUpdate: number ): boolean { return ( - this.tileSizePixelsWalked + pixelsToWalkThisUpdate >= AkkamonWorldScene.TILE_SIZE + this.tileSizePixelsWalked + pixelsToWalkThisUpdate >= TILE_SIZE ); } diff --git a/client/src/akkamon/render/engine/RemotePlayerEngine.ts b/client/src/akkamon/render/engine/RemotePlayerEngine.ts index 65d54bf..7ce5fa9 100644 --- a/client/src/akkamon/render/engine/RemotePlayerEngine.ts +++ b/client/src/akkamon/render/engine/RemotePlayerEngine.ts @@ -1,6 +1,6 @@ import Phaser from 'phaser'; -import type { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import type { WorldScene } from '../../scenes/WorldScene'; import { AkkamonEngine } from '../engine/AkkamonEngine'; import type { Direction } from '../Direction'; @@ -10,20 +10,23 @@ import { } from '../model/RemotePlayerSprite'; import { - Queue + Queue, + baseQueue, + queueFromArray } from '../../DataWrappers'; -import type { - RemoteMovementQueues -} from '../../client/Events'; + +type RemoteMovementQueues = { + [key: string]: {value: Direction[]} +} export class RemotePlayerEngine extends AkkamonEngine { - private scene: AkkamonWorldScene; + private scene: WorldScene; private trainerIdToRemotePlayerSprite: Map<string, RemotePlayerSprite> = new Map(); - constructor(scene: AkkamonWorldScene) { + constructor(scene: WorldScene) { super(); this.scene = scene; } @@ -69,7 +72,7 @@ export class RemotePlayerEngine extends AkkamonEngine { tilePos: new Phaser.Math.Vector2(this.scene.spawnPointTilePos!), texture: this.scene.textures.get("atlas"), frame: "misa-front", - moveQueue: new Queue(moveQueue) + moveQueue: queueFromArray(moveQueue) } )); } else { diff --git a/client/src/akkamon/render/model/PlayerSprite.ts b/client/src/akkamon/render/model/PlayerSprite.ts index ec44295..2c4160e 100644 --- a/client/src/akkamon/render/model/PlayerSprite.ts +++ b/client/src/akkamon/render/model/PlayerSprite.ts @@ -1,5 +1,5 @@ import Phaser from 'phaser'; -import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import { WorldScene, TILE_SIZE } from '../../scenes/WorldScene'; import type { Direction } from '../Direction'; @@ -18,12 +18,12 @@ export class PlayerSprite extends Phaser.GameObjects.Sprite implements AkkamonPl tilePos: Phaser.Math.Vector2; constructor(config: PlayerSpriteConfig) { - const offsetX = AkkamonWorldScene.TILE_SIZE / 2; - const offsetY = AkkamonWorldScene.TILE_SIZE; + const offsetX = TILE_SIZE / 2; + const offsetY = TILE_SIZE; super(config.scene, - config.tilePos.x * AkkamonWorldScene.TILE_SIZE + offsetX, - config.tilePos.y * AkkamonWorldScene.TILE_SIZE + offsetY, + config.tilePos.x * TILE_SIZE + offsetX, + config.tilePos.y * TILE_SIZE + offsetY, config.texture, config.frame); diff --git a/client/src/akkamon/render/model/RemotePlayerSprite.ts b/client/src/akkamon/render/model/RemotePlayerSprite.ts index aae911f..0e64992 100644 --- a/client/src/akkamon/render/model/RemotePlayerSprite.ts +++ b/client/src/akkamon/render/model/RemotePlayerSprite.ts @@ -1,10 +1,13 @@ import Phaser from 'phaser'; -import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import { TILE_SIZE } from '../../scenes/WorldScene'; import { PlayerSprite } from '../model/PlayerSprite'; import { GridPhysics } from '../engine/GridPhysics'; import { Direction } from '../Direction'; -import { Queue } from '../../DataWrappers'; +import { + Queue, + baseQueue +} from '../../DataWrappers'; type RemotePlayerSpriteConfig = { scene: Phaser.Scene, @@ -17,11 +20,11 @@ type RemotePlayerSpriteConfig = { export class RemotePlayerSprite extends PlayerSprite { private lastTilePos?: Phaser.Math.Vector2; - private moveQueue: Queue<Direction> = new Queue(); + private moveQueue: Queue<Direction> = baseQueue(); private movementDirection: Direction = Direction.NONE; - private speedPixelsPerSecond: number = AkkamonWorldScene.TILE_SIZE * 4; + private speedPixelsPerSecond: number = TILE_SIZE * 4; private tileSizePixelsWalked: number = 0; @@ -46,7 +49,7 @@ export class RemotePlayerSprite extends PlayerSprite { } else if (this.shouldContinueMoving()) { this.move(pixelsToWalkThisUpdate); } else { - this.move(AkkamonWorldScene.TILE_SIZE - this.tileSizePixelsWalked); + this.move(TILE_SIZE - this.tileSizePixelsWalked); this.stopMoving(); } } @@ -61,12 +64,12 @@ export class RemotePlayerSprite extends PlayerSprite { } willCrossTileBorderThisUpdate(pixelsToWalkThisUpdate: number): boolean { - return (this.tileSizePixelsWalked + pixelsToWalkThisUpdate) >= AkkamonWorldScene.TILE_SIZE; + return (this.tileSizePixelsWalked + pixelsToWalkThisUpdate) >= TILE_SIZE; } move(pixelsToMove: number): void { this.tileSizePixelsWalked += pixelsToMove; - this.tileSizePixelsWalked %= AkkamonWorldScene.TILE_SIZE; + this.tileSizePixelsWalked %= TILE_SIZE; const directionVec = GridPhysics.movementDirectionVectors[this.movementDirection]!.clone(); diff --git a/client/src/akkamon/scenes/AkkamonWorldScene.ts b/client/src/akkamon/scenes/AkkamonWorldScene.ts index c478757..002b4b5 100644 --- a/client/src/akkamon/scenes/AkkamonWorldScene.ts +++ b/client/src/akkamon/scenes/AkkamonWorldScene.ts @@ -4,133 +4,282 @@ import { client } from '../../app'; import { PauseMenu, AkkamonMenu } from '../scenes/UIElement'; -import { Stack } from '../DataWrappers'; +import { + Stack, + baseStack +} from '../DataWrappers'; export let eventsCenter = new Phaser.Events.EventEmitter(); -export class AkkamonWorldScene extends Phaser.Scene { - static readonly TILE_SIZE = 32; +export interface WorldScene extends Phaser.Scene { - map?: Phaser.Tilemaps.Tilemap; + client: typeof client; - client = client; - - eventsCenter = eventsCenter; - - public spawnPointTilePos?: { + map?: Phaser.Tilemaps.Tilemap + spawnPoint?: Phaser.Types.Tilemaps.TiledObject; + spawnPointTilePos?: { x: number, y: number }; - spawnPoint: Phaser.Types.Tilemaps.TiledObject | undefined; - - menus: Stack<AkkamonMenu> = new Stack(); - - create(mapKey: string, tileSetKey: string) { - this.map = this.make.tilemap({ key: mapKey }); - // Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in - // Phaser's cache (i.e. the name you used in preload) - const tileset = this.map.addTilesetImage(tileSetKey, "tiles"); - // Parameters: layer name (or index) from Tiled, tileset, x, y - const belowLayer = this.map.createLayer("Below Player", tileset, 0, 0); - const worldLayer = this.map.createLayer("World", tileset, 0, 0); - const aboveLayer = this.map.createLayer("Above Player", tileset, 0, 0); - // By default, everything gets depth sorted on the screen in the order we created things. Here, we - // want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth. - // Higher depths will sit on top of lower depth objects. - aboveLayer.setDepth(10); - - this.spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point"); - - var tilePos = new Phaser.Math.Vector2( - Math.floor(this.spawnPoint.x! / AkkamonWorldScene.TILE_SIZE), - Math.floor(this.spawnPoint.y! / AkkamonWorldScene.TILE_SIZE), - ); - this.spawnPointTilePos = tilePos; - - this.client.requestInitPlayerSprite( - this - ); - - let akey = this.input.keyboard.addKey('a'); - akey.on('down', () => { - if (this.menus.isEmpty()) { - this.pushMenu(new PauseMenu(this)); - } - }); - // this.add.image( - // this.spawnPoint.x!, - // this.spawnPoint.y!, - // 'pikachu-back', - // ) - // .setDepth(30) - // .setDisplaySize(500,500) - // .setOrigin(0.5, 0.5) + create: (mapKey: string, tileSetKey: string) => void - } + menus: Stack<AkkamonMenu>; - menuTakesUIControl(input: Phaser.Input.InputPlugin, menu: AkkamonMenu) { - this.client.setUIControls(input, menu); - } + menuTakesUIControl: (input: Phaser.Input.InputPlugin, menu: AkkamonMenu) => void - isUsingGridControls() { - this.client.setGridControls(); - } + isUsingGridControls: () => void - pushMenu(menu: AkkamonMenu) { - this.menus.push(menu); - this.menuTakesUIControl(this.input, menu); - console.log("New menu stack:"); - console.log(this.menus); - } + pushMenu: (menu: AkkamonMenu) => void + popMenu: () => void - popMenu() { - return this.menus.pop(); - } + traverseMenusBackwards: () => void - traverseMenusBackwards() { - this.popMenu(); - if (!this.menus.isEmpty()) { - this.menuTakesUIControl(this.input, this.menus.peek()); - } else { - this.isUsingGridControls(); - } - console.log("menu stack after traversing back:"); - console.log(this.menus); - } + getPlayerPixelPosition: () => Phaser.Math.Vector2 - getPlayerPixelPosition(): Phaser.Math.Vector2 { - return this.client.requestPlayerPixelPosition(); - } + getRemotePlayerNames: () => string[] - getRemotePlayerNames(): Array<string> { - let remotePlayerData = this.client.requestRemotePlayerData(); - if (remotePlayerData.size === 0) { - return ['Nobody Online']; - } else { - return Array.from(remotePlayerData.keys()); - } - } + requestBattle: (remotePlayerData: string | string[]) => void - requestBattle(remotePlayerName: string | string[]): void { - this.client.sendInteractionRequest({ - type: "battle", - requestingTrainerId: this.client.getSessionTrainerId()!, - receivingTrainerIds: Array.isArray(remotePlayerName) ? remotePlayerName : [remotePlayerName] - }); - } + clearMenus: () => void +} - clearMenus() { - if (this.menus.length > 0) { - this.menus.pop()!.destroyGroup(); - console.log("stack while clearing menus:"); - console.log(this.menus.cloneData()); - this.clearMenus(); - } - } +export function akkamonBaseWorldScene(key: string): WorldScene { + let phaserScene = new Phaser.Scene(key); + return { + ... phaserScene, + + client: client, + + menus: baseStack(), + + create: function(mapKey: string, tileSetKey: string): void { + this.map = this.make.tilemap({ key: mapKey }); + // Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in + // Phaser's cache (i.e. the name you used in preload) + const tileset = this.map.addTilesetImage(tileSetKey, "tiles"); + // Parameters: layer name (or index) from Tiled, tileset, x, y + const belowLayer = this.map.createLayer("Below Player", tileset, 0, 0); + const worldLayer = this.map.createLayer("World", tileset, 0, 0); + const aboveLayer = this.map.createLayer("Above Player", tileset, 0, 0); + // By default, everything gets depth sorted on the screen in the order we created things. Here, we + // want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth. + // Higher depths will sit on top of lower depth objects. + aboveLayer.setDepth(10); + + this.spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point"); - setWaitingOnResponse() { + var tilePos = new Phaser.Math.Vector2( + Math.floor(this.spawnPoint.x! / TILE_SIZE), + Math.floor(this.spawnPoint.y! / TILE_SIZE), + ); + this.spawnPointTilePos = tilePos; + this.client.requestInitPlayerSprite( + this + ); + + let akey = this.input.keyboard.addKey('a'); + akey.on('down', () => { + if (this.menus.isEmpty()) { + this.pushMenu(new PauseMenu(this)); + } + }); + + // this.add.image( + // this.spawnPoint.x!, + // this.spawnPoint.y!, + // 'pikachu-back', + // ) + // .setDepth(30) + // .setDisplaySize(500,500) + // .setOrigin(0.5, 0.5) + + }, + + update: function(time: number, delta: number): void { + }, + + menuTakesUIControl: function (input: Phaser.Input.InputPlugin, menu: AkkamonMenu): void { + this.client.setUIControls(input, menu); + }, + + isUsingGridControls: function () { + this.client.setGridControls(); + }, + + pushMenu: function (menu: AkkamonMenu) { + this.menus.push(menu); + this.menuTakesUIControl(this.input, menu); + console.log("New menu stack:"); + console.log(this.menus); + }, + + popMenu: function () { + return this.menus.pop(); + }, + + traverseMenusBackwards: function () { + this.popMenu(); + if (!this.menus.isEmpty()) { + this.menuTakesUIControl(this.input, this.menus.peek()!); + } else { + this.isUsingGridControls(); + } + console.log("menu stack after traversing back:"); + console.log(this.menus); + }, + + getPlayerPixelPosition: function (): Phaser.Math.Vector2 { + return this.client.requestPlayerPixelPosition(); + }, + + getRemotePlayerNames: function (): Array<string> { + let remotePlayerData = this.client.requestRemotePlayerData(); + if (remotePlayerData.size === 0) { + return ['Nobody Online']; + } else { + return Array.from(remotePlayerData.keys()); + } + }, + + requestBattle: function (remotePlayerName: string | string[]): void { + this.client.sendInteractionRequest({ + type: "battle", + requestingTrainerId: this.client.getSessionTrainerId()!, + receivingTrainerIds: Array.isArray(remotePlayerName) ? remotePlayerName : [remotePlayerName] + }); + }, + + clearMenus: function () { + if (this.menus.size() > 0) { + this.menus.pop()!.destroyGroup(); + console.log("stack while clearing menus:"); + console.log(this.menus.cloneData()); + this.clearMenus(); + } + }, } } + + +// export class WorldScene extends Phaser.Scene { +// static readonly TILE_SIZE = 32; +// +// map?: Phaser.Tilemaps.Tilemap; +// +// client = client; +// +// spawnPoint: Phaser.Types.Tilemaps.TiledObject | undefined; +// +// menus: Stack<AkkamonMenu> = baseStack(); +// +// create(mapKey: string, tileSetKey: string) { +// this.map = this.make.tilemap({ key: mapKey }); +// // Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in +// // Phaser's cache (i.e. the name you used in preload) +// const tileset = this.map.addTilesetImage(tileSetKey, "tiles"); +// // Parameters: layer name (or index) from Tiled, tileset, x, y +// const belowLayer = this.map.createLayer("Below Player", tileset, 0, 0); +// const worldLayer = this.map.createLayer("World", tileset, 0, 0); +// const aboveLayer = this.map.createLayer("Above Player", tileset, 0, 0); +// // By default, everything gets depth sorted on the screen in the order we created things. Here, we +// // want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth. +// // Higher depths will sit on top of lower depth objects. +// aboveLayer.setDepth(10); +// +// this.spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point"); +// +// var tilePos = new Phaser.Math.Vector2( +// Math.floor(this.spawnPoint.x! / TILE_SIZE), +// Math.floor(this.spawnPoint.y! / TILE_SIZE), +// ); +// this.spawnPointTilePos = tilePos; +// +// this.client.requestInitPlayerSprite( +// this +// ); +// +// let akey = this.input.keyboard.addKey('a'); +// akey.on('down', () => { +// if (this.menus.isEmpty()) { +// this.pushMenu(new PauseMenu(this)); +// } +// }); +// +// // this.add.image( +// // this.spawnPoint.x!, +// // this.spawnPoint.y!, +// // 'pikachu-back', +// // ) +// // .setDepth(30) +// // .setDisplaySize(500,500) +// // .setOrigin(0.5, 0.5) +// +// } +// +// menuTakesUIControl(input: Phaser.Input.InputPlugin, menu: AkkamonMenu) { +// this.client.setUIControls(input, menu); +// } +// +// isUsingGridControls() { +// this.client.setGridControls(); +// } +// +// pushMenu(menu: AkkamonMenu) { +// this.menus.push(menu); +// this.menuTakesUIControl(this.input, menu); +// console.log("New menu stack:"); +// console.log(this.menus); +// } +// +// popMenu() { +// return this.menus.pop(); +// } +// +// traverseMenusBackwards() { +// this.popMenu(); +// if (!this.menus.isEmpty()) { +// this.menuTakesUIControl(this.input, this.menus.peek()!); +// } else { +// this.isUsingGridControls(); +// } +// console.log("menu stack after traversing back:"); +// console.log(this.menus); +// } +// +// getPlayerPixelPosition(): Phaser.Math.Vector2 { +// return this.client.requestPlayerPixelPosition(); +// } +// +// getRemotePlayerNames(): Array<string> { +// let remotePlayerData = this.client.requestRemotePlayerData(); +// if (remotePlayerData.size === 0) { +// return ['Nobody Online']; +// } else { +// return Array.from(remotePlayerData.keys()); +// } +// } +// +// requestBattle(remotePlayerName: string | string[]): void { +// this.client.sendInteractionRequest({ +// type: "battle", +// requestingTrainerId: this.client.getSessionTrainerId()!, +// receivingTrainerIds: Array.isArray(remotePlayerName) ? remotePlayerName : [remotePlayerName] +// }); +// } +// +// clearMenus() { +// if (this.menus.size() > 0) { +// this.menus.pop()!.destroyGroup(); +// console.log("stack while clearing menus:"); +// console.log(this.menus.cloneData()); +// this.clearMenus(); +// } +// } +// +// setWaitingOnResponse() { +// +// } +// } diff --git a/client/src/akkamon/scenes/BootScene.ts b/client/src/akkamon/scenes/BootScene.ts index af70953..d3d8dba 100644 --- a/client/src/akkamon/scenes/BootScene.ts +++ b/client/src/akkamon/scenes/BootScene.ts @@ -1,44 +1,47 @@ import Phaser from 'phaser'; -import { AkkamonWorldScene } from './AkkamonWorldScene'; +import type { + BasePhaserScene +} from '../PhaserTypes'; -export class BootScene extends AkkamonWorldScene { - constructor() { - super('BootScene') - } - - init(): void { - } +import { WorldScene } from './WorldScene'; - preload(): void { - this.load.image("tiles", "assets/tilesets/akkamon-demo-extruded.png"); - // load from json! - this.load.tilemapTiledJSON("map", "assets/tilemaps/akkamon-demo-tilemap.json"); +function createBootScene<PhaserScene extends BasePhaserScene>(base: PhaserScene, sceneKey: string) { + return class BootScene extends base { + preload(): void { + this.load.image("tiles", "assets/tilesets/akkamon-demo-extruded.png"); + // load from json! + this.load.tilemapTiledJSON("map", "assets/tilemaps/akkamon-demo-tilemap.json"); - // An atlas is a way to pack multiple images together into one texture. I'm using it to load all - // the player animations (walking left, walking right, etc.) in one image. For more info see: + // An atlas is a way to pack multiple images together into one texture. I'm using it to load all + // the player animations (walking left, walking right, etc.) in one image. For more info see: - // https://labs.phaser.io/view.html?src=src/animation/texture%20atlas%20animation.js - // If you don't use an atlas, you can do the same thing with a spritesheet, see: - // https://labs.phaser.io/view.html?src=src/animation/single%20sprite%20sheet.js - this.load.atlas("atlas", - "assets/atlas/atlas.png", - "assets/atlas/atlas.json"); + // https://labs.phaser.io/view.html?src=src/animation/texture%20atlas%20animation.js + // If you don't use an atlas, you can do the same thing with a spritesheet, see: + // https://labs.phaser.io/view.html?src=src/animation/single%20sprite%20sheet.js + this.load.atlas("atlas", + "assets/atlas/atlas.png", + "assets/atlas/atlas.json"); - this.load.image("menu", "assets/images/pMenu.png"); - this.load.image("picker", "assets/images/menupicker.png"); + this.load.image("menu", "assets/images/pMenu.png"); + this.load.image("picker", "assets/images/menupicker.png"); - this.load.pack("pokemon-yellow-front", "assets/pokemon/main-sprites/yellow/pokemon-yellow-front.json") - this.load.pack("pokemon-yellow-back", "assets/pokemon/main-sprites/yellow/pokemon-yellow-back.json") + this.load.pack("pokemon-yellow-front", "assets/pokemon/main-sprites/yellow/pokemon-yellow-front.json") + this.load.pack("pokemon-yellow-back", "assets/pokemon/main-sprites/yellow/pokemon-yellow-back.json") - this.load.pack("general-interface", "assets/images/general-ui.json") - this.load.pack("battle-interface", "assets/images/battle-ui.json") - } + this.load.pack("general-interface", "assets/images/general-ui.json") + this.load.pack("battle-interface", "assets/images/battle-ui.json") + } - create(): void { - this.scene + create(): void { + this.scene .launch('DemoScene') .remove() + } } } + +let BootScene = createBootScene(Phaser.Scene, "BootScene"); + +export default BootScene; diff --git a/client/src/akkamon/scenes/DemoScene.ts b/client/src/akkamon/scenes/DemoScene.ts index 66da72f..9544df3 100644 --- a/client/src/akkamon/scenes/DemoScene.ts +++ b/client/src/akkamon/scenes/DemoScene.ts @@ -1,23 +1,14 @@ import Phaser from 'phaser'; -import { AkkamonWorldScene } from './AkkamonWorldScene'; +import type { + BasePhaserScene +} from '../PhaserTypes'; -export class DemoScene extends AkkamonWorldScene -{ - constructor () - { - super('DemoScene'); - } +import { + WorldScene, + createWorldScene +} from './WorldScene'; - create () - { - super.create("map", "akkamon-demo-extruded"); - } +let DemoScene = createWorldScene(Phaser.Scene, "DemoScene", "map", "akkamon-demo-extruded"); - - update(time: number, delta: number) { - this.client.updateScene(delta); - } - - -} +export default DemoScene; diff --git a/client/src/akkamon/scenes/UIElement.ts b/client/src/akkamon/scenes/UIElement.ts index ec7ffd3..03cce88 100644 --- a/client/src/akkamon/scenes/UIElement.ts +++ b/client/src/akkamon/scenes/UIElement.ts @@ -1,6 +1,7 @@ -import type { AkkamonWorldScene } from '../scenes/AkkamonWorldScene'; +import type { WorldScene } from '../scenes/WorldScene'; import { Direction } from '../render/Direction'; import { + baseQueue, Queue } from '../DataWrappers'; @@ -71,7 +72,7 @@ export interface AkkamonMenu { class Menu extends Phaser.GameObjects.Image implements AkkamonMenu { - akkamonScene: AkkamonWorldScene + akkamonScene: WorldScene public group?: Phaser.GameObjects.Group; @@ -104,7 +105,7 @@ class Menu extends Phaser.GameObjects.Image implements AkkamonMenu { throw new Error('Confirm method should be present in a Menu implementation'); } - constructor(scene: AkkamonWorldScene, imageKey: string) { + constructor(scene: WorldScene, imageKey: string) { let camera = scene.cameras.main; super(scene, camera.scrollX, camera.scrollY, imageKey) @@ -177,7 +178,7 @@ class Menu extends Phaser.GameObjects.Image implements AkkamonMenu { } export class PauseMenu extends Menu implements AkkamonMenu { - constructor(scene: AkkamonWorldScene) { + constructor(scene: WorldScene) { super(scene, "pause-menu") let camera = scene.cameras.main; this.setPosition(this.x + camera.width, this.y); @@ -206,7 +207,7 @@ class ListMenu extends Menu implements AkkamonMenu { viewBot: number = 4; constructor( - scene: AkkamonWorldScene, + scene: WorldScene, options: Array<string> ) { super(scene, "pause-menu") @@ -296,7 +297,7 @@ class ConfirmationDialogue extends Menu implements AkkamonMenu { options?: Array<string> dialogueBox?: Dialogue - constructor(scene: AkkamonWorldScene, options: Array<string>, dialogueData: {[key: string]: string}) { + constructor(scene: WorldScene, options: Array<string>, dialogueData: {[key: string]: string}) { super(scene, "confirmation-dialogue"); let camera = scene.cameras.main; this.setDisplaySize(200, 0.83 * 200) @@ -317,10 +318,10 @@ class ConfirmationDialogue extends Menu implements AkkamonMenu { class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu { public messageQueue: Queue<string>; public displayedText: MenuText; - public akkamonScene: AkkamonWorldScene; + public akkamonScene: WorldScene; public group: Phaser.GameObjects.Group; - constructor(scene: AkkamonWorldScene, group: Phaser.GameObjects.Group, depth: number) { + constructor(scene: WorldScene, group: Phaser.GameObjects.Group, depth: number) { let camera = scene.cameras.main; super(scene, camera.scrollX, camera.scrollY, "general-dialogue-box") this.setOrigin(0,1); @@ -334,7 +335,7 @@ class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu { this.group = group; this.akkamonScene = scene; - this.messageQueue = new Queue(); + this.messageQueue = baseQueue(); this.displayedText = new WrappedMenuText( this.akkamonScene, this.group, @@ -402,7 +403,7 @@ class Dialogue extends Phaser.GameObjects.Image implements AkkamonMenu { class ChallengeDialogue extends ConfirmationDialogue implements AkkamonMenu { challengedTrainerName: string; - constructor(scene: AkkamonWorldScene, options: Array<string>, dialogueData: {[key: string]: string}) { + constructor(scene: WorldScene, options: Array<string>, dialogueData: {[key: string]: string}) { super(scene, options, dialogueData); this.challengedTrainerName = dialogueData['trainerName']; this.dialogueBox!.push( @@ -429,7 +430,7 @@ class ChallengeDialogue extends ConfirmationDialogue implements AkkamonMenu { class WaitingDialogue extends Dialogue { waitingPrinter: any - constructor(scene: AkkamonWorldScene, group: Phaser.GameObjects.Group, depth: number) { + constructor(scene: WorldScene, group: Phaser.GameObjects.Group, depth: number) { super(scene, group, depth); this.typewriteText("Waiting on reponse..."); this.waitingPrinter = setInterval(() => { diff --git a/client/src/akkamon/scenes/UIScene.ts b/client/src/akkamon/scenes/UIScene.ts index 199a847..7b1b9e9 100644 --- a/client/src/akkamon/scenes/UIScene.ts +++ b/client/src/akkamon/scenes/UIScene.ts @@ -1,3 +1,3 @@ import { Direction } from '../render/Direction'; -import { eventsCenter } from '../../akkamon/scenes/AkkamonWorldScene'; +import { eventsCenter } from '../../akkamon/scenes/WorldScene'; diff --git a/client/src/akkamon/scenes/WorldScene.ts b/client/src/akkamon/scenes/WorldScene.ts new file mode 100644 index 0000000..fd866aa --- /dev/null +++ b/client/src/akkamon/scenes/WorldScene.ts @@ -0,0 +1,167 @@ +import Phaser from 'phaser'; + +import { client } from '../../app'; + +import { PauseMenu, AkkamonMenu } from '../scenes/UIElement'; + +import type { + BasePhaserScene +} from '../PhaserTypes'; + +import { + Stack, + baseStack +} from '../DataWrappers'; + +export let TILE_SIZE = 32; + +export interface WorldScene extends Phaser.Scene { + + client: typeof client; + + map?: Phaser.Tilemaps.Tilemap + spawnPoint?: Phaser.Types.Tilemaps.TiledObject; + spawnPointTilePos?: { + x: number, + y: number + }; + + + create: () => void + + menus: Stack<AkkamonMenu>; + + menuTakesUIControl: (input: Phaser.Input.InputPlugin, menu: AkkamonMenu) => void + + isUsingGridControls: () => void + + pushMenu: (menu: AkkamonMenu) => void + popMenu: () => void + + traverseMenusBackwards: () => void + + getPlayerPixelPosition: () => Phaser.Math.Vector2 + + getRemotePlayerNames: () => string[] + + requestBattle: (remotePlayerData: string | string[]) => void + + clearMenus: () => void +} + + +export function createWorldScene<PhaserScene extends BasePhaserScene>(scene: PhaserScene, sceneKey: string, mapKey: string, tileSetKey: string) { + return class WorldScene extends scene implements WorldScene { + map?: Phaser.Tilemaps.Tilemap; + + client = client; + + menus = baseStack<AkkamonMenu>(); + + spawnPoint?: Phaser.Types.Tilemaps.TiledObject; + spawnPointTilePos?: { + x: number, + y: number + }; + + constructor(... params: any[]) { + super(sceneKey); + } + + create() { + this.map = this.make.tilemap({ key: mapKey }); + // Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in + // Phaser's cache (i.e. the name you used in preload) + const tileset = this.map.addTilesetImage(tileSetKey, "tiles"); + // Parameters: layer name (or index) from Tiled, tileset, x, y + const belowLayer = this.map.createLayer("Below Player", tileset, 0, 0); + const worldLayer = this.map.createLayer("World", tileset, 0, 0); + const aboveLayer = this.map.createLayer("Above Player", tileset, 0, 0); + // By default, everything gets depth sorted on the screen in the order we created things. Here, we + // want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth. + // Higher depths will sit on top of lower depth objects. + aboveLayer.setDepth(10); + + this.spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point"); + + var tilePos = new Phaser.Math.Vector2( + Math.floor(this.spawnPoint.x! / TILE_SIZE), + Math.floor(this.spawnPoint.y! / TILE_SIZE), + ); + this.spawnPointTilePos = tilePos; + + this.client.requestInitWorldScene( + this + ); + + let akey = this.input.keyboard.addKey('a'); + akey.on('down', () => { + if (this.menus.isEmpty()) { + this.pushMenu(new PauseMenu(this)); + } + }); + + } + + menuTakesUIControl(input: Phaser.Input.InputPlugin, menu: AkkamonMenu): void { + this.client.setUIControls(input, menu); + } + + isUsingGridControls() { + this.client.setGridControls(); + } + + pushMenu(menu: AkkamonMenu) { + this.menus.push(menu); + this.menuTakesUIControl(this.input, menu); + console.log("New menu stack:"); + console.log(this.menus); + } + + popMenu() { + return this.menus.pop(); + } + + traverseMenusBackwards() { + this.popMenu(); + if (!this.menus.isEmpty()) { + this.menuTakesUIControl(this.input, this.menus.peek()!); + } else { + this.isUsingGridControls(); + } + console.log("menu stack after traversing back:"); + console.log(this.menus); + } + + getPlayerPixelPosition(): Phaser.Math.Vector2 { + return this.client.requestPlayerPixelPosition(); + } + + getRemotePlayerNames(): Array<string> { + let remotePlayerData = this.client.requestRemotePlayerData(); + if (remotePlayerData.size === 0) { + return ['Nobody Online']; + } else { + return Array.from(remotePlayerData.keys()); + } + } + + requestBattle(remotePlayerName: string | string[]): void { + this.client.sendInteractionRequest({ + type: "battle", + requestingTrainerId: this.client.getSessionTrainerId()!, + receivingTrainerIds: Array.isArray(remotePlayerName) ? remotePlayerName : [remotePlayerName] + }); + } + + clearMenus() { + if (this.menus.size() > 0) { + this.menus.pop()!.destroyGroup(); + console.log("stack while clearing menus:"); + console.log(this.menus.cloneData()); + this.clearMenus(); + } + } + + } +} diff --git a/client/src/app.ts b/client/src/app.ts index 05fccb5..7a80442 100644 --- a/client/src/app.ts +++ b/client/src/app.ts @@ -15,6 +15,8 @@ import Phaser from 'phaser'; import { gameConfig } from './akkamon/GameConfig'; import { Client } from './akkamon/client/Client'; +export var client = new Client('ws://localhost:8080'); + function newGame () { if (game) return; game = new Phaser.Game(gameConfig); @@ -26,7 +28,6 @@ function destroyGame () { game = null; } -export let client = new Client('ws://localhost:8080'); let game: Phaser.Game | null | undefined; |
