diff options
| author | Mike Vink <mike1994vink@gmail.com> | 2021-07-23 22:09:20 +0200 |
|---|---|---|
| committer | Mike Vink <mike1994vink@gmail.com> | 2021-07-23 22:09:20 +0200 |
| commit | 4692175208a8f0526c6e0881aa0e51345c5574fb (patch) | |
| tree | 4753635cc27e319933384b703b357ee86318a3fd /client | |
| parent | eaff86546eca516d51c27eb9d63ea33a96576e90 (diff) | |
feat(): start ui
Diffstat (limited to 'client')
22 files changed, 596 insertions, 192 deletions
diff --git a/client/dist/assets/images/menupicker.png b/client/dist/assets/images/menupicker.png Binary files differnew file mode 100644 index 0000000..e8bc3e2 --- /dev/null +++ b/client/dist/assets/images/menupicker.png 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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="150.52913" + height="225.5291" + viewBox="0 0 39.8275 59.671237" + version="1.1" + id="svg5" + inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)" + sodipodi:docname="menupicker.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview7" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="true" + inkscape:document-units="mm" + showgrid="true" + width="200px" + borderlayer="true" + inkscape:showpageshadow="false" + inkscape:snap-global="true" + inkscape:snap-bbox="true" + inkscape:bbox-paths="false" + inkscape:bbox-nodes="true" + inkscape:snap-others="false" + units="px" + inkscape:zoom="2.8284271" + inkscape:cx="78.312076" + inkscape:cy="99.52528" + inkscape:window-width="1594" + inkscape:window-height="894" + inkscape:window-x="0" + inkscape:window-y="1440" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + <inkscape:grid + type="xygrid" + id="grid21" + spacingx="6.6145834" + spacingy="6.6145834" + empspacing="1" + dotted="true" + originx="-396.80503" + originy="-350.50289" /> + </sodipodi:namedview> + <defs + id="defs2"> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath1350"> + <rect + style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.140441;stroke-dasharray:0.140441, 0.702204;stroke-opacity:1;marker-start:none;marker-end:none" + id="rect1352" + width="72.760414" + height="72.760414" + x="13.229166" + y="-79.375" /> + </clipPath> + </defs> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-396.80501,-350.50293)"> + <g + id="g1950" + style="stroke:#000000;stroke-opacity:1" + transform="translate(978.95832,165.3646)"> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1624" + width="39.6875" + height="6.614583" + x="-582.08331" + y="211.66666" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1628" + width="26.458332" + height="6.614583" + x="-582.08331" + y="205.05208" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1630" + width="19.84375" + height="6.614583" + x="-582.08331" + y="198.43748" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1632" + width="13.229166" + height="6.614583" + x="-582.08331" + y="191.82291" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1634" + width="6.614583" + height="6.614583" + x="-582.08331" + y="185.20833" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1636" + width="26.458332" + height="6.614583" + x="-582.08331" + y="218.28123" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1638" + width="19.84375" + height="6.614583" + x="-582.08331" + y="224.89583" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1640" + width="13.229166" + height="6.614583" + x="-582.08331" + y="231.51041" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1642" + width="6.614583" + height="6.614583" + x="-582.08331" + y="238.12498" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1757" + width="6.614583" + height="6.614583" + x="-555.625" + y="218.28123" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1759" + width="6.614583" + height="6.614583" + x="-562.23956" + y="224.89583" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1761" + width="6.614583" + height="6.614583" + x="-568.85419" + y="231.51041" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1763" + width="6.614583" + height="6.614583" + x="-575.46875" + y="238.12498" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1765" + width="6.614583" + height="6.614583" + x="-555.625" + y="205.05208" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1767" + width="6.614583" + height="6.614583" + x="-562.23956" + y="198.43748" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1769" + width="6.614583" + height="6.614583" + x="-568.85419" + y="191.82291" /> + <rect + style="fill:#000000;stroke:#000000;stroke-width:0.14;stroke-opacity:1" + id="rect1771" + width="6.614583" + height="6.614583" + x="-575.46875" + y="185.20833" /> + </g> + </g> +</svg> diff --git a/client/dist/assets/images/pMenu.png b/client/dist/assets/images/pMenu.png Binary files differnew file mode 100644 index 0000000..715741b --- /dev/null +++ b/client/dist/assets/images/pMenu.png 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<string, RemotePlayerSprite> = 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<T> { 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<MenuText>; + + 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(); |
