From 4692175208a8f0526c6e0881aa0e51345c5574fb Mon Sep 17 00:00:00 2001 From: Mike Vink Date: Fri, 23 Jul 2021 22:09:20 +0200 Subject: feat(): start ui --- api/src/main/java/akkamon/api/MessagingEngine.java | 2 +- client/dist/assets/images/menupicker.png | Bin 0 -> 1039 bytes client/dist/assets/images/menupicker.svg | 202 +++++++++++++++++++++ client/dist/assets/images/pMenu.png | Bin 0 -> 56628 bytes client/src/akkamon/GameConfig.ts | 19 ++ client/src/akkamon/client/AkkamonClient.ts | 2 + client/src/akkamon/client/Client.ts | 92 +++++++++- client/src/akkamon/client/Events.ts | 2 +- client/src/akkamon/client/Socket.ts | 6 +- client/src/akkamon/render/DirectionToAnimation.ts | 15 ++ client/src/akkamon/render/GridControls.ts | 2 +- client/src/akkamon/render/engine/AkkamonEngine.ts | 7 + client/src/akkamon/render/engine/GridPhysics.ts | 37 ++-- .../akkamon/render/engine/RemotePlayerEngine.ts | 21 ++- client/src/akkamon/render/model/PlayerSprite.ts | 13 +- .../src/akkamon/render/model/RemotePlayerSprite.ts | 16 +- client/src/akkamon/scenes/AkkamonWorldScene.ts | 23 +++ client/src/akkamon/scenes/BootScene.ts | 39 ++++ client/src/akkamon/scenes/DemoScene.ts | 132 ++------------ client/src/akkamon/scenes/Pack.ts | 1 + client/src/akkamon/scenes/UIElement.ts | 3 + client/src/akkamon/scenes/UIScene.ts | 119 +++++++++++- client/src/app.ts | 37 ++-- .../src/main/java/akkamon/domain/AkkamonNexus.java | 8 +- 24 files changed, 601 insertions(+), 197 deletions(-) create mode 100644 client/dist/assets/images/menupicker.png create mode 100644 client/dist/assets/images/menupicker.svg create mode 100644 client/dist/assets/images/pMenu.png create mode 100644 client/src/akkamon/GameConfig.ts create mode 100644 client/src/akkamon/client/AkkamonClient.ts create mode 100644 client/src/akkamon/render/DirectionToAnimation.ts create mode 100644 client/src/akkamon/render/engine/AkkamonEngine.ts create mode 100644 client/src/akkamon/scenes/AkkamonWorldScene.ts create mode 100644 client/src/akkamon/scenes/BootScene.ts create mode 100644 client/src/akkamon/scenes/Pack.ts create mode 100644 client/src/akkamon/scenes/UIElement.ts diff --git a/api/src/main/java/akkamon/api/MessagingEngine.java b/api/src/main/java/akkamon/api/MessagingEngine.java index 3d3cd96..11a0c66 100644 --- a/api/src/main/java/akkamon/api/MessagingEngine.java +++ b/api/src/main/java/akkamon/api/MessagingEngine.java @@ -104,7 +104,7 @@ public class MessagingEngine implements AkkamonMessageEngine { void incoming(AkkamonSession session, String message) { Event event = gson.fromJson(message, Event.class); // TODO use session trainerId - String sceneId = "akkamonStartScene"; + String sceneId = "DemoScene"; switch (event.type) { case START_MOVING: diff --git a/client/dist/assets/images/menupicker.png b/client/dist/assets/images/menupicker.png new file mode 100644 index 0000000..e8bc3e2 Binary files /dev/null and b/client/dist/assets/images/menupicker.png differ diff --git a/client/dist/assets/images/menupicker.svg b/client/dist/assets/images/menupicker.svg new file mode 100644 index 0000000..9cf911f --- /dev/null +++ b/client/dist/assets/images/menupicker.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/dist/assets/images/pMenu.png b/client/dist/assets/images/pMenu.png new file mode 100644 index 0000000..715741b Binary files /dev/null and b/client/dist/assets/images/pMenu.png differ diff --git a/client/src/akkamon/GameConfig.ts b/client/src/akkamon/GameConfig.ts new file mode 100644 index 0000000..11fc26a --- /dev/null +++ b/client/src/akkamon/GameConfig.ts @@ -0,0 +1,19 @@ +import { + UIScene +} from './scenes/UIScene'; +import { + DemoScene +} from './scenes/DemoScene'; +import { + BootScene +} from './scenes/BootScene'; + + +export const gameConfig: Phaser.Types.Core.GameConfig & Phaser.Types.Core.RenderConfig = { + type: Phaser.AUTO, + backgroundColor: '#125555', + width: 800, + height: 600, + pixelArt: true, + scene: [BootScene, DemoScene, UIScene] +}; diff --git a/client/src/akkamon/client/AkkamonClient.ts b/client/src/akkamon/client/AkkamonClient.ts new file mode 100644 index 0000000..db84385 --- /dev/null +++ b/client/src/akkamon/client/AkkamonClient.ts @@ -0,0 +1,2 @@ +export interface AkkamonClient { +} diff --git a/client/src/akkamon/client/Client.ts b/client/src/akkamon/client/Client.ts index 8f9115f..b0caa98 100644 --- a/client/src/akkamon/client/Client.ts +++ b/client/src/akkamon/client/Client.ts @@ -1,23 +1,39 @@ -import type AkkamonSession from './session'; -import { Socket } from './socket'; -import type { GridPhysics } from './GridPhysics'; -import type { RemotePlayerEngine } from './RemotePlayerEngine'; +import type AkkamonSession from './Session'; +import { Socket } from './Socket'; + +import { PlayerSprite } from '../render/model/PlayerSprite'; +import { GridPhysics } from '../render/engine/GridPhysics'; +import { GridControls } from '../render/GridControls'; + +import { RemotePlayerEngine } from '../render/engine/RemotePlayerEngine'; + +import type { AkkamonClient } from './AkkamonClient'; + +import type { AkkamonWorldScene } from '../scenes/AkkamonWorldScene'; + +import { DirectionToAnimation } from '../render/DirectionToAnimation'; +import { Direction } from '../render/Direction'; import { EventType, HeartBeatReplyEvent, IncomingEvent, AkkamonEvent, -} from './events'; +} from './Events'; -export class Client +export class Client implements AkkamonClient { private session: AkkamonSession; + + private scene?: AkkamonWorldScene; private gridPhysics?: GridPhysics; + private gridControls?: GridControls; + private remotePlayerEngine?: RemotePlayerEngine; + constructor( url: string ) { @@ -47,8 +63,68 @@ export class Client } } - setRemotePlayerEngine(engine: RemotePlayerEngine) { - this.remotePlayerEngine = engine; + updateScene(delta: number): void { + this.gridControls!.update(); + this.gridPhysics!.update(delta); + this.remotePlayerEngine!.update(delta); + } + + requestInitPlayerSprite( + scene: AkkamonWorldScene + ): void { + + this.scene = scene; + + let playerSprite = new PlayerSprite({ + scene: scene, + tilePos: new Phaser.Math.Vector2(scene.spawnPointTilePos!), + texture: scene.textures.get("atlas"), + frame: "misa-front" + }); + + this.gridPhysics = new GridPhysics( + playerSprite, + scene.map! + ); + + this.gridControls = new GridControls( + scene.input, + this.gridPhysics + ); + + this.remotePlayerEngine = new RemotePlayerEngine( + scene + ); + this.initAnimation(scene, playerSprite); + } + + private initAnimation( + scene: AkkamonWorldScene, + player: PlayerSprite + ): void { + + this.createPlayerAnimation(scene, Direction.LEFT, 0, 3); + this.createPlayerAnimation(scene, Direction.RIGHT, 0, 3); + this.createPlayerAnimation(scene, Direction.UP, 0, 3); + this.createPlayerAnimation(scene, Direction.DOWN, 0, 3); + + // Phaser supports multiple cameras, but you can access the default camera like this: + const camera = scene.cameras.main; + camera.startFollow(player); + camera.roundPixels = true; + camera.setBounds(0, 0, scene.map!.widthInPixels, scene.map!.heightInPixels); + } + + private createPlayerAnimation(scene: AkkamonWorldScene, direction: Direction, start: number, end: number) { + let characterAnimations = DirectionToAnimation.directionToAnimation['misa']; + + scene.anims.create({ + key: direction, // "misa-left-walk", + frames: scene.anims.generateFrameNames("atlas", { prefix: characterAnimations[direction] + ".", start: start, end: end, zeroPad: 3 }), + frameRate: 10, + repeat: -1 + }); + } } diff --git a/client/src/akkamon/client/Events.ts b/client/src/akkamon/client/Events.ts index 1954fd7..830ac23 100644 --- a/client/src/akkamon/client/Events.ts +++ b/client/src/akkamon/client/Events.ts @@ -1,5 +1,5 @@ import Phaser from 'phaser'; -import type { Direction } from './Direction'; +import type { Direction } from '../render/Direction'; export enum EventType { HEART_BEAT = "HeartBeat", diff --git a/client/src/akkamon/client/Socket.ts b/client/src/akkamon/client/Socket.ts index 4e83f89..e0c3e0c 100644 --- a/client/src/akkamon/client/Socket.ts +++ b/client/src/akkamon/client/Socket.ts @@ -1,9 +1,9 @@ import Phaser from 'phaser'; -import type { Client } from './client' -import type AkkamonSession from './session' +import type { Client } from './Client' +import type AkkamonSession from './Session' import { PlayerRegistrationEvent -} from './events'; +} from './Events'; export class Socket extends WebSocket implements AkkamonSession { diff --git a/client/src/akkamon/render/DirectionToAnimation.ts b/client/src/akkamon/render/DirectionToAnimation.ts new file mode 100644 index 0000000..0e3969d --- /dev/null +++ b/client/src/akkamon/render/DirectionToAnimation.ts @@ -0,0 +1,15 @@ +import { Direction } from './Direction'; + +export class DirectionToAnimation { + static readonly directionToAnimation: { + [name: string]: { [key in Direction]: string } + } = {misa: + { + [Direction.UP]: "misa-back-walk", + [Direction.DOWN]: "misa-front-walk", + [Direction.LEFT]: "misa-left-walk", + [Direction.RIGHT]: "misa-right-walk", + [Direction.NONE]: "misa-front-walk" + } + } +} diff --git a/client/src/akkamon/render/GridControls.ts b/client/src/akkamon/render/GridControls.ts index d7feef2..40f3789 100644 --- a/client/src/akkamon/render/GridControls.ts +++ b/client/src/akkamon/render/GridControls.ts @@ -1,5 +1,5 @@ import { Direction } from './Direction'; -import type { GridPhysics } from './GridPhysics'; +import type { GridPhysics } from '../render/engine/GridPhysics'; export class GridControls { private cursors: Phaser.Types.Input.Keyboard.CursorKeys; diff --git a/client/src/akkamon/render/engine/AkkamonEngine.ts b/client/src/akkamon/render/engine/AkkamonEngine.ts new file mode 100644 index 0000000..14dae86 --- /dev/null +++ b/client/src/akkamon/render/engine/AkkamonEngine.ts @@ -0,0 +1,7 @@ +import { client } from '../../../app'; + + +export class AkkamonEngine { + client = client; + +} diff --git a/client/src/akkamon/render/engine/GridPhysics.ts b/client/src/akkamon/render/engine/GridPhysics.ts index b1fe459..2f1c080 100644 --- a/client/src/akkamon/render/engine/GridPhysics.ts +++ b/client/src/akkamon/render/engine/GridPhysics.ts @@ -1,17 +1,20 @@ import Phaser from 'phaser'; -import type { PlayerSprite } from './sprite'; -import { Direction } from './Direction'; -import AkkamonStartScene from './scene'; -import { - akkamonClient -} from './app'; + +import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; + +import { AkkamonEngine } from './AkkamonEngine'; + +import type { PlayerSprite } from '../model/PlayerSprite'; + +import { Direction } from '../Direction'; + import { StartMovingEvent, StopMovingEvent, NewTilePosEvent -} from './events'; +} from '../../client/Events'; -export class GridPhysics { +export class GridPhysics extends AkkamonEngine { static movementDirectionVectors: { [key in Direction]?: Phaser.Math.Vector2; @@ -23,7 +26,7 @@ export class GridPhysics { } private movementDirection: Direction = Direction.NONE; - private readonly speedPixelsPerSecond: number = AkkamonStartScene.TILE_SIZE * 4; + private readonly speedPixelsPerSecond: number = AkkamonWorldScene.TILE_SIZE * 4; private tileSizePixelsWalked: number = 0; @@ -32,7 +35,9 @@ export class GridPhysics { constructor( private playerSprite: PlayerSprite, private tileMap: Phaser.Tilemaps.Tilemap - ) { } + ) { + super() + } movePlayerSprite(direction: Direction): void { this.lastMovementIntent = direction; @@ -52,7 +57,7 @@ export class GridPhysics { private startMoving(direction: Direction): void { console.log("Sending startMovingEvent"); - akkamonClient.send( + this.client.send( new StartMovingEvent(this.playerSprite.getScene(), direction) ); this.playerSprite.startAnimation(direction); @@ -76,13 +81,13 @@ export class GridPhysics { this.spriteMovement(pixelsToWalkThisUpdate); this.updatePlayerSpriteTilePosition(); } else { - this.spriteMovement(AkkamonStartScene.TILE_SIZE - this.tileSizePixelsWalked); + this.spriteMovement(AkkamonWorldScene.TILE_SIZE - this.tileSizePixelsWalked); this.stopMoving(); } } private updatePlayerSpriteTilePosition() { - akkamonClient.send( + this.client.send( new NewTilePosEvent( this.playerSprite.getScene(), this.playerSprite.getTilePos() @@ -106,7 +111,7 @@ export class GridPhysics { private spriteMovement(pixelsToMove: number) { this.tileSizePixelsWalked += pixelsToMove; - this.tileSizePixelsWalked %= AkkamonStartScene.TILE_SIZE; + this.tileSizePixelsWalked %= AkkamonWorldScene.TILE_SIZE; const directionVec = GridPhysics.movementDirectionVectors[ @@ -125,7 +130,7 @@ export class GridPhysics { pixelsToWalkThisUpdate: number ): boolean { return ( - this.tileSizePixelsWalked + pixelsToWalkThisUpdate >= AkkamonStartScene.TILE_SIZE + this.tileSizePixelsWalked + pixelsToWalkThisUpdate >= AkkamonWorldScene.TILE_SIZE ); } @@ -135,7 +140,7 @@ export class GridPhysics { } private stopMoving(): void { - akkamonClient.send( + this.client.send( new StopMovingEvent( this.playerSprite.getScene(), this.movementDirection diff --git a/client/src/akkamon/render/engine/RemotePlayerEngine.ts b/client/src/akkamon/render/engine/RemotePlayerEngine.ts index 5d85f24..917453b 100644 --- a/client/src/akkamon/render/engine/RemotePlayerEngine.ts +++ b/client/src/akkamon/render/engine/RemotePlayerEngine.ts @@ -1,22 +1,27 @@ import Phaser from 'phaser'; -import type AkkamonStartScene from './scene'; -import { akkamonClient } from './app'; -import type { Direction } from './Direction'; + +import type { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import { AkkamonEngine } from '../engine/AkkamonEngine'; + +import type { Direction } from '../Direction'; + import { Queue, RemotePlayerSprite -} from './RemotePlayerSprite'; +} from '../model/RemotePlayerSprite'; + import type { RemoteMovementQueues -} from './events'; +} from '../../client/Events'; -export class RemotePlayerEngine { +export class RemotePlayerEngine extends AkkamonEngine { - private scene: AkkamonStartScene; + private scene: AkkamonWorldScene; private trainerIdToRemotePlayerSprite: Map = new Map(); - constructor(scene: AkkamonStartScene) { + constructor(scene: AkkamonWorldScene) { + super(); this.scene = scene; } diff --git a/client/src/akkamon/render/model/PlayerSprite.ts b/client/src/akkamon/render/model/PlayerSprite.ts index 948d8d9..ec44295 100644 --- a/client/src/akkamon/render/model/PlayerSprite.ts +++ b/client/src/akkamon/render/model/PlayerSprite.ts @@ -1,6 +1,7 @@ import Phaser from 'phaser'; -import AkkamonStartScene from './scene'; -import type { Direction } from './Direction'; +import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; + +import type { Direction } from '../Direction'; type PlayerSpriteConfig = { scene: Phaser.Scene, @@ -17,12 +18,12 @@ export class PlayerSprite extends Phaser.GameObjects.Sprite implements AkkamonPl tilePos: Phaser.Math.Vector2; constructor(config: PlayerSpriteConfig) { - const offsetX = AkkamonStartScene.TILE_SIZE / 2; - const offsetY = AkkamonStartScene.TILE_SIZE; + const offsetX = AkkamonWorldScene.TILE_SIZE / 2; + const offsetY = AkkamonWorldScene.TILE_SIZE; super(config.scene, - config.tilePos.x * AkkamonStartScene.TILE_SIZE + offsetX, - config.tilePos.y * AkkamonStartScene.TILE_SIZE + offsetY, + config.tilePos.x * AkkamonWorldScene.TILE_SIZE + offsetX, + config.tilePos.y * AkkamonWorldScene.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 6103d09..0b8d3e9 100644 --- a/client/src/akkamon/render/model/RemotePlayerSprite.ts +++ b/client/src/akkamon/render/model/RemotePlayerSprite.ts @@ -1,8 +1,8 @@ import Phaser from 'phaser'; -import AkkamonStartScene from './scene'; -import { PlayerSprite } from './sprite'; -import { GridPhysics } from './GridPhysics'; -import { Direction } from './Direction'; +import { AkkamonWorldScene } from '../../scenes/AkkamonWorldScene'; +import { PlayerSprite } from '../model/PlayerSprite'; +import { GridPhysics } from '../engine/GridPhysics'; +import { Direction } from '../Direction'; export class Queue { private _data = new Array(); @@ -51,7 +51,7 @@ export class RemotePlayerSprite extends PlayerSprite { private movementDirection: Direction = Direction.NONE; - private speedPixelsPerSecond: number = AkkamonStartScene.TILE_SIZE * 4; + private speedPixelsPerSecond: number = AkkamonWorldScene.TILE_SIZE * 4; private tileSizePixelsWalked: number = 0; @@ -76,7 +76,7 @@ export class RemotePlayerSprite extends PlayerSprite { } else if (this.shouldContinueMoving()) { this.move(pixelsToWalkThisUpdate); } else { - this.move(AkkamonStartScene.TILE_SIZE - this.tileSizePixelsWalked); + this.move(AkkamonWorldScene.TILE_SIZE - this.tileSizePixelsWalked); this.stopMoving(); } } @@ -91,12 +91,12 @@ export class RemotePlayerSprite extends PlayerSprite { } willCrossTileBorderThisUpdate(pixelsToWalkThisUpdate: number): boolean { - return (this.tileSizePixelsWalked + pixelsToWalkThisUpdate) >= AkkamonStartScene.TILE_SIZE; + return (this.tileSizePixelsWalked + pixelsToWalkThisUpdate) >= AkkamonWorldScene.TILE_SIZE; } move(pixelsToMove: number): void { this.tileSizePixelsWalked += pixelsToMove; - this.tileSizePixelsWalked %= AkkamonStartScene.TILE_SIZE; + this.tileSizePixelsWalked %= AkkamonWorldScene.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 new file mode 100644 index 0000000..b9cfc20 --- /dev/null +++ b/client/src/akkamon/scenes/AkkamonWorldScene.ts @@ -0,0 +1,23 @@ +import Phaser from 'phaser'; + +import { client } from '../../app'; + +export let eventsCenter = new Phaser.Events.EventEmitter(); + +export class AkkamonWorldScene extends Phaser.Scene { + static readonly TILE_SIZE = 32; + + map?: Phaser.Tilemaps.Tilemap; + + client = client; + + eventsCenter = eventsCenter; + + public spawnPointTilePos?: { + x: number, + y: number + }; + + spawnPoint: Phaser.Types.Tilemaps.TiledObject | undefined; + +} diff --git a/client/src/akkamon/scenes/BootScene.ts b/client/src/akkamon/scenes/BootScene.ts new file mode 100644 index 0000000..4642584 --- /dev/null +++ b/client/src/akkamon/scenes/BootScene.ts @@ -0,0 +1,39 @@ +import Phaser from 'phaser'; + +import { AkkamonWorldScene } from './AkkamonWorldScene'; + +export class BootScene extends AkkamonWorldScene { + constructor() { + super('BootScene') + } + + init(): void { + } + + 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: + + // 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("menupicker", "assets/images/menupicker.png"); + } + + create(): void { + this.scene + .launch('DemoScene') + .launch('AkkamonUI') + .remove() + } +} + diff --git a/client/src/akkamon/scenes/DemoScene.ts b/client/src/akkamon/scenes/DemoScene.ts index c301457..b9a230a 100644 --- a/client/src/akkamon/scenes/DemoScene.ts +++ b/client/src/akkamon/scenes/DemoScene.ts @@ -1,146 +1,54 @@ import Phaser from 'phaser'; -import { PlayerSprite } from './sprite'; -import { GridControls } from './GridControls'; -import { GridPhysics } from './GridPhysics'; -import { Direction } from './Direction'; +import { AkkamonWorldScene } from './AkkamonWorldScene'; -import { RemotePlayerEngine } from './RemotePlayerEngine'; - -import { UIControls } from './uiControls'; - -import { akkamonClient } from './app'; - -export default class AkkamonStartScene extends Phaser.Scene +export class DemoScene extends AkkamonWorldScene { - - static readonly TILE_SIZE = 32; - - private gridPhysics?: GridPhysics - private gridControls?: GridControls - - private remotePlayerEngine?: RemotePlayerEngine - - public spawnPointTilePos?: { - x: number, - y: number - }; - - directionToAnimation: { - [key in Direction]: string - } = { - [Direction.UP]: "misa-back-walk", - [Direction.DOWN]: "misa-front-walk", - [Direction.LEFT]: "misa-left-walk", - [Direction.RIGHT]: "misa-right-walk", - [Direction.NONE]: "misa-front-walk" - } - - spawnPoint: Phaser.Types.Tilemaps.TiledObject | undefined; - - constructor () { - super('akkamonStartScene'); - } - - preload () - { - 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: - - // 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"); + super('DemoScene'); } - create () { - const map = this.make.tilemap({ key: "map" }); + this.map = this.make.tilemap({ key: "map" }); // 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 = map.addTilesetImage("akkamon-demo-extruded", "tiles"); + const tileset = this.map.addTilesetImage("akkamon-demo-extruded", "tiles"); // Parameters: layer name (or index) from Tiled, tileset, x, y - const belowLayer = map.createLayer("Below Player", tileset, 0, 0); - const worldLayer = map.createLayer("World", tileset, 0, 0); - const aboveLayer = map.createLayer("Above Player", tileset, 0, 0); + 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 = map.findObject("Objects", obj => obj.name === "Spawn Point"); - - //this.createPlayerAnimation(Direction.UP); - - - // Create a sprite with physics enabled via the physics system. The image used for the sprite has - // a bit of whitespace, so I'm using setSize & setOffset to control the size of the player's body. + this.spawnPoint = this.map.findObject("Objects", obj => obj.name === "Spawn Point"); var tilePos = new Phaser.Math.Vector2( - Math.floor(this.spawnPoint.x! / AkkamonStartScene.TILE_SIZE), - Math.floor(this.spawnPoint.y! / AkkamonStartScene.TILE_SIZE), + Math.floor(this.spawnPoint.x! / AkkamonWorldScene.TILE_SIZE), + Math.floor(this.spawnPoint.y! / AkkamonWorldScene.TILE_SIZE), ); this.spawnPointTilePos = tilePos; - let player = new PlayerSprite({ - scene: this, - tilePos: tilePos, - texture: this.textures.get("atlas"), - frame: "misa-front", - }); - - this.gridPhysics = new GridPhysics(player, map); - this.gridControls = new GridControls( - this.input, - this.gridPhysics + this.client.requestInitPlayerSprite( + this ); - this.remotePlayerEngine = new RemotePlayerEngine(this); - akkamonClient.setRemotePlayerEngine(this.remotePlayerEngine); - - this.createPlayerAnimation(Direction.LEFT, 0, 3); - this.createPlayerAnimation(Direction.RIGHT, 0, 3); - this.createPlayerAnimation(Direction.UP, 0, 3); - this.createPlayerAnimation(Direction.DOWN, 0, 3); - - // Phaser supports multiple cameras, but you can access the default camera like this: - const camera = this.cameras.main; - camera.startFollow(player); - camera.roundPixels = true; - camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels); + let akey = this.input.keyboard.addKey('a'); + akey.on('down', () => { + this.input.keyboard.enabled = false; + this.eventsCenter.emit('open-menu'); + // this.client.disableGridControls(); + }); } update(time: number, delta: number) { - this.gridControls!.update(); - this.gridPhysics!.update(delta); - this.remotePlayerEngine!.update(delta); + this.client.updateScene(delta); } - private createPlayerAnimation(direction: Direction, start: number, end: number) { - this.anims.create({ - key: direction, // "misa-left-walk", - frames: this.anims.generateFrameNames("atlas", { prefix: this.directionToAnimation[direction] + ".", start: start, end: end, zeroPad: 3 }), - frameRate: 10, - repeat: -1 - }); - -// anims.create({ -// key: "misa-left-walk", -// frames: anims.generateFrameNames("atlas", { prefix: "misa-left-walk.", start: 0, end: 3, zeroPad: 3 }), -// frameRate: 10, -// repeat: -1 - - } } diff --git a/client/src/akkamon/scenes/Pack.ts b/client/src/akkamon/scenes/Pack.ts new file mode 100644 index 0000000..a89c860 --- /dev/null +++ b/client/src/akkamon/scenes/Pack.ts @@ -0,0 +1 @@ +import assets from './Assets'; diff --git a/client/src/akkamon/scenes/UIElement.ts b/client/src/akkamon/scenes/UIElement.ts new file mode 100644 index 0000000..f48827d --- /dev/null +++ b/client/src/akkamon/scenes/UIElement.ts @@ -0,0 +1,3 @@ +export enum UIElement { + MAIN_MENU = "main-menu" +} diff --git a/client/src/akkamon/scenes/UIScene.ts b/client/src/akkamon/scenes/UIScene.ts index 3dc7ee9..de415f8 100644 --- a/client/src/akkamon/scenes/UIScene.ts +++ b/client/src/akkamon/scenes/UIScene.ts @@ -1,20 +1,125 @@ -import { UIControls } from './uiControls'; +import { Direction } from '../render/Direction'; +import { eventsCenter } from '../../akkamon/scenes/AkkamonWorldScene'; -export class AkkamonUI extends Phaser.Scene +class MenuText extends Phaser.GameObjects.Text { + constructor(scene: Phaser.Scene, group: Phaser.GameObjects.Group, x: number, y: number, text: string) { + let style: Phaser.Types.GameObjects.Text.TextStyle = { + fontFamily: 'Courier', + fontSize: '16px', + fontStyle: '', + backgroundColor: undefined, + color: '#000000', + stroke: '#000000', + strokeThickness: 0, + align: 'left', // 'left'|'center'|'right'|'justify' + } + super(scene, x, y, text, style); + scene.add.existing(this); + group.add(this); + } +} + +interface AkkamonMenu { +} + +class Menu extends Phaser.GameObjects.Image implements AkkamonMenu { + + private buttons?: Array; + + private buttonSelector?: Phaser.GameObjects.Image; + + private selectedButton?: string; + + private index?: number; + + public group?: Phaser.GameObjects.Group; + + constructor(scene: Phaser.Scene) { + const { width, height } = scene.scale; + super(scene, width * 0.95, height * 0.05, "menu") + this.setOrigin(1,0) + this.setVisible(true) + this.setDisplaySize(296, 400) + + this.group = new Phaser.GameObjects.Group(scene); + + scene.add.existing(this); + this.group.add(this); + + this.buttons = new Array(); + + this.setMainButtons(); + + this.buttonSelector = scene.add.image( + this.x - this.displayWidth + 40, + this.buttons![0].y + 7, + "menupicker") + .setDisplaySize(20,33) + .setOrigin(0.5,0.5); + this.group.add(this.buttonSelector); + + this.index = 0; + this.selectedButton = this.buttons[0].text; + } + + resetPicker() { + this.buttonSelector! + .setPosition(this.x - this.displayWidth + 40, + this.buttons![0].y + 7); + } + + setMainButtons() { + this.buttons!.push(new MenuText(this.scene, this.group!, this.x - 150, this.y + 40, 'POKéDEX')); + this.buttons!.push(new MenuText(this.scene, this.group!, this.x - 150, this.y + 140, 'POKéMON')); + this.buttons!.push(new MenuText(this.scene, this.group!, this.x - 150, this.y + 240, 'PHONE')); + this.buttons!.push(new MenuText(this.scene, this.group!, this.x - 150, this.y + 340, 'CLOSE')); + } + + clearButtons() { + this.buttons = new Array(); + } + + selectButton(direction: Direction) { + if (direction === Direction.UP && this.index! !== 0) { + this.buttonSelector! + .setPosition(this.buttonSelector!.x, this.buttonSelector!.y - 100) + this.index! -= 1; + } else if (direction === Direction.DOWN && this.index !== this.buttons!.length - 1) { + this.buttonSelector! + .setPosition(this.buttonSelector!.x, this.buttonSelector!.y + 100) + this.index! += 1; + } + + this.selectedButton = this.buttons![this.index!].text; + } +} + +export class UIScene extends Phaser.Scene { - private uiControls: UIControls; + // private uiControls: UIControls; + + private cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + + private menu?: Menu; constructor () { super('AkkamonUI'); } - preload() { - } - create () { - this.uiControls = new UIControls(this.input); + //this.uiControls = new UIControls(this.input); + + + this.menu = new Menu(this); + this.menu.group!.setVisible(false); + + eventsCenter.on('open-menu', () => + { + this.menu!.group!.setVisible(true); + }); + } } diff --git a/client/src/app.ts b/client/src/app.ts index c6bad67..197fb63 100644 --- a/client/src/app.ts +++ b/client/src/app.ts @@ -1,26 +1,19 @@ -// import Phaser from 'phaser'; -import AkkamonStartScene from './scene'; -import { AkkamonUI } from './uiScene'; -import { Client } from './client'; - -const serviceUrl = 'ws://localhost:8080'; - -export const akkamonClient = new Client(serviceUrl); - -const config: Phaser.Types.Core.GameConfig & Phaser.Types.Core.RenderConfig = { - type: Phaser.AUTO, - backgroundColor: '#125555', - width: 800, - height: 600, - pixelArt: true, - scene: [AkkamonStartScene, AkkamonUI] -}; - -const game: Phaser.Game = new Phaser.Game(config); +// // import Phaser from 'phaser'; +// import AkkamonStartScene from './scene'; +// import { AkkamonUI } from './uiScene'; +// import { Client } from './client'; +// +// const serviceUrl = 'ws://localhost:8080'; +// +// export const akkamonClient = new Client(serviceUrl); +// +// +// const game: Phaser.Game = new Phaser.Game(config); import Phaser from 'phaser'; -import gameConfig from './app/gameConfig.js'; +import { gameConfig } from './akkamon/GameConfig'; +import { Client } from './akkamon/client/Client'; function newGame () { if (game) return; @@ -30,10 +23,10 @@ function newGame () { function destroyGame () { if (!game) return; game.destroy(true); - game.runDestroy(); game = null; } -let game; +export let client = new Client('ws://localhost:8080'); +let game: Phaser.Game | null | undefined; if (!game) newGame(); diff --git a/domain/src/main/java/akkamon/domain/AkkamonNexus.java b/domain/src/main/java/akkamon/domain/AkkamonNexus.java index a55e728..d467df7 100644 --- a/domain/src/main/java/akkamon/domain/AkkamonNexus.java +++ b/domain/src/main/java/akkamon/domain/AkkamonNexus.java @@ -236,7 +236,7 @@ public class AkkamonNexus extends AbstractBehavior { if (sceneTrainerGroup != null) { sceneTrainerGroup.tell(trainerOfflineRequest); } else { - getContext().getLog().info("Ignoring trainerOffline request in scene {}, it isn't mapped to a sceneTrainerActor."); + getContext().getLog().info("Ignoring trainerOffline request in scene {}, it isn't mapped to a sceneTrainerActor.", trainerOfflineRequest.sceneId); } return this; } @@ -273,7 +273,7 @@ public class AkkamonNexus extends AbstractBehavior { if (sceneTrainerGroup != null) { sceneTrainerGroup.tell(newTilePosRequest); } else { - getContext().getLog().info("Ignoring newTilePos request in scene {}, it isn't mapped to a sceneTrainerActor."); + getContext().getLog().info("Ignoring newTilePos request in scene {}, it isn't mapped to a sceneTrainerActor.", newTilePosRequest.sceneId); } return this; } @@ -285,7 +285,7 @@ public class AkkamonNexus extends AbstractBehavior { if (sceneTrainerGroup != null) { sceneTrainerGroup.tell(stopMovingRequest); } else { - getContext().getLog().info("Ignoring stopMove request in scene {}, it isn't mapped to a sceneTrainerActor."); + getContext().getLog().info("Ignoring stopMove request in scene {}, it isn't mapped to a sceneTrainerActor.", stopMovingRequest.sceneId); } return this; } @@ -297,7 +297,7 @@ public class AkkamonNexus extends AbstractBehavior { if (sceneTrainerGroup != null) { sceneTrainerGroup.tell(startMovingRequest); } else { - getContext().getLog().info("Ignoring stopMove request in scene {}, it isn't mapped to a sceneTrainerActor."); + getContext().getLog().info("Ignoring startMove request in scene {}, it isn't mapped to a sceneTrainerActor.", startMovingRequest.sceneId); } return this; } -- cgit v1.2.3