summaryrefslogtreecommitdiff
path: root/client/src/akkamon
diff options
context:
space:
mode:
authorMike Vink <mike1994vink@gmail.com>2021-07-28 16:52:08 +0200
committerMike Vink <mike1994vink@gmail.com>2021-07-28 16:52:08 +0200
commit9e675c3652eb7a16ce5c2a865c030c76653c921e (patch)
tree6ae24d621eb38b832ba6d6595d2ad87b6f1ec5aa /client/src/akkamon
parent4d84c12df52c89abb7d3ba9f565753116b99dbf0 (diff)
feat(): refactor after playing with mixins
Diffstat (limited to 'client/src/akkamon')
-rw-r--r--client/src/akkamon/DataWrappers.ts125
-rw-r--r--client/src/akkamon/GameConfig.ts8
-rw-r--r--client/src/akkamon/PhaserTypes.ts3
-rw-r--r--client/src/akkamon/client/Client.ts45
-rw-r--r--client/src/akkamon/client/EventType.ts16
-rw-r--r--client/src/akkamon/client/Events.ts104
-rw-r--r--client/src/akkamon/client/IncomingEvents.ts47
-rw-r--r--client/src/akkamon/client/InteractionEngine.ts17
-rw-r--r--client/src/akkamon/client/OutgoingEvents.ts78
-rw-r--r--client/src/akkamon/render/engine/GridPhysics.ts12
-rw-r--r--client/src/akkamon/render/engine/RemotePlayerEngine.ts19
-rw-r--r--client/src/akkamon/render/model/PlayerSprite.ts10
-rw-r--r--client/src/akkamon/render/model/RemotePlayerSprite.ts17
-rw-r--r--client/src/akkamon/scenes/AkkamonWorldScene.ts361
-rw-r--r--client/src/akkamon/scenes/BootScene.ts61
-rw-r--r--client/src/akkamon/scenes/DemoScene.ts27
-rw-r--r--client/src/akkamon/scenes/UIElement.ts23
-rw-r--r--client/src/akkamon/scenes/UIScene.ts2
-rw-r--r--client/src/akkamon/scenes/WorldScene.ts167
19 files changed, 767 insertions, 375 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();
+ }
+ }
+
+ }
+}