From 17d75324f8d833556133eccdfa1ec1b0496384b0 Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 19 Dec 2024 16:17:07 -0800 Subject: [PATCH] hit space bar for alternate view --- TODO.txt | 6 +- src/client/InputHandler.ts | 25 ++++++ src/client/graphics/GameRenderer.ts | 2 +- src/client/graphics/layers/UnitLayer.ts | 105 ++++++++++++++++++------ src/core/configuration/Config.ts | 4 + src/core/configuration/DevConfig.ts | 6 +- src/core/configuration/PastelTheme.ts | 15 ++++ 7 files changed, 131 insertions(+), 32 deletions(-) diff --git a/TODO.txt b/TODO.txt index f4f3806cd..81832030e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -243,14 +243,16 @@ * store and archive player cookies DONE 12/17/2024 * make ips less precise for user safety DONE 12/17/2024 * send client logs back to server DONE 12/18/2024 -* render more info in info overlay +* render more info in info overlay DONE 12/19/2024 +* create alternate view for freinds enemies DONE 12/19/2024 +* give naval units health +* create more prominant discord link * right click brings up player info menu * create new view for enemies & personal units * send client logs back to server DONE 12/17/2024 * make info panel merge with X, display more info * right click brings up player info menu * seperate server config from client config -* give naval units health * bug: player names not updating sometimes * make player editeable configs * couldn't scroll left on build menu to deploy bombs (mobile) diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts index 54de8490f..2b590cd35 100644 --- a/src/client/InputHandler.ts +++ b/src/client/InputHandler.ts @@ -44,6 +44,10 @@ export class DragEvent implements GameEvent { ) { } } +export class AlternateViewEvent implements GameEvent { + constructor(public readonly alternateView: boolean) { } +} + export class InputHandler { private lastPointerX: number = 0; @@ -58,6 +62,8 @@ export class InputHandler { private pointerDown: boolean = false + private alternateView = false + constructor(private canvas: HTMLCanvasElement, private eventBus: EventBus) { } initialize() { @@ -72,6 +78,25 @@ export class InputHandler { this.eventBus.emit(new MouseMoveEvent(e.clientX, e.clientY)) }); this.pointers.clear() + + + window.addEventListener('keydown', (e) => { + if (e.code === 'Space') { + e.preventDefault(); // Prevent page scrolling + if (!this.alternateView) { + this.alternateView = true + this.eventBus.emit(new AlternateViewEvent(true)) + } + } + }); + + window.addEventListener('keyup', (e) => { + if (e.code === 'Space') { + e.preventDefault(); + this.alternateView = false + this.eventBus.emit(new AlternateViewEvent(false)) + } + }); } private onPointerDown(event: PointerEvent) { diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index a35459948..e3b0d1f18 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -75,7 +75,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: new TerrainLayer(game), new TerritoryLayer(game, eventBus), new StructureLayer(game, eventBus), - new UnitLayer(game, eventBus), + new UnitLayer(game, eventBus, clientID), new NameLayer(game, game.config().theme(), transformHandler, clientID), new UILayer(eventBus, game, clientID, transformHandler), eventsDisplay, diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index 8d0d94062..8cc18dc9d 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -1,10 +1,17 @@ import { Colord } from "colord"; import { Theme } from "../../../core/configuration/Config"; -import { Unit, UnitEvent, Cell, Game, Tile, UnitType } from "../../../core/game/Game"; +import { Unit, UnitEvent, Cell, Game, Tile, UnitType, Player } from "../../../core/game/Game"; import { bfs, dist, euclDist } from "../../../core/Util"; import { Layer } from "./Layer"; import { EventBus } from "../../../core/EventBus"; -import { consolex } from "../../../core/Consolex"; +import { AlternateViewEvent } from "../../InputHandler"; +import { ClientID } from "../../../core/Schemas"; + +enum Relationship { + Self, + Ally, + Enemy +} export class UnitLayer implements Layer { private canvas: HTMLCanvasElement; @@ -14,7 +21,12 @@ export class UnitLayer implements Layer { private theme: Theme = null; - constructor(private game: Game, private eventBus: EventBus) { + private alternateView = false + + private myPlayer: Player | null = null + + + constructor(private game: Game, private eventBus: EventBus, private clientID: ClientID) { this.theme = game.config().theme(); } @@ -24,6 +36,9 @@ export class UnitLayer implements Layer { } tick() { + if (this.myPlayer == null) { + this.myPlayer = this.game.playerByClientID(this.clientID) + } } init(game: Game) { @@ -34,6 +49,7 @@ export class UnitLayer implements Layer { this.canvas.height = this.game.height(); this.eventBus.on(UnitEvent, e => this.onUnitEvent(e)); + this.eventBus.on(AlternateViewEvent, e => this.onAlternativeViewEvent(e)) } renderLayer(context: CanvasRenderingContext2D) { @@ -46,6 +62,31 @@ export class UnitLayer implements Layer { ); } + onAlternativeViewEvent(event: AlternateViewEvent) { + this.alternateView = event.alternateView + this.redraw() + } + + + redraw() { + for (const unit of this.game.units()) { + this.onUnitEvent(new UnitEvent(unit, unit.tile())) + } + } + + private relationship(unit: Unit): Relationship { + if (this.myPlayer == null) { + return Relationship.Enemy + } + if (this.myPlayer == unit.owner()) { + return Relationship.Self + } + if (this.myPlayer.isAlliedWith(unit.owner())) { + return Relationship.Ally + } + return Relationship.Enemy + } + onUnitEvent(event: UnitEvent) { switch (event.unit.type()) { case UnitType.TransportShip: @@ -71,6 +112,7 @@ export class UnitLayer implements Layer { } private handleDestroyerEvent(event: UnitEvent) { + const rel = this.relationship(event.unit) bfs(event.oldTile, euclDist(event.oldTile, 4)).forEach(t => { this.clearCell(t.cell()); }); @@ -78,12 +120,13 @@ export class UnitLayer implements Layer { return } bfs(event.unit.tile(), euclDist(event.unit.tile(), 4)) - .forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255)); bfs(event.unit.tile(), dist(event.unit.tile(), 3)) - .forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255)); } private handleBattleshipEvent(event: UnitEvent) { + const rel = this.relationship(event.unit) bfs(event.oldTile, euclDist(event.oldTile, 6)).forEach(t => { this.clearCell(t.cell()); }); @@ -91,48 +134,52 @@ export class UnitLayer implements Layer { return } bfs(event.unit.tile(), euclDist(event.unit.tile(), 5)) - .forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255)); bfs(event.unit.tile(), dist(event.unit.tile(), 4)) - .forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255)); bfs(event.unit.tile(), euclDist(event.unit.tile(), 1)) - .forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255)); } private handleShellEvent(event: UnitEvent) { + const rel = this.relationship(event.unit) this.clearCell(event.oldTile.cell()) if (!event.unit.isActive()) { return } - this.paintCell(event.unit.tile().cell(), this.theme.borderColor(event.unit.owner().info()), 255) + this.paintCell(event.unit.tile().cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255) } private handleNuke(event: UnitEvent) { + const rel = this.relationship(event.unit) bfs(event.oldTile, euclDist(event.oldTile, 2)).forEach(t => { this.clearCell(t.cell()); }); if (event.unit.isActive()) { bfs(event.unit.tile(), euclDist(event.unit.tile(), 2)) - .forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255)); } } private handleTradeShipEvent(event: UnitEvent) { + const rel = this.relationship(event.unit) bfs(event.oldTile, euclDist(event.oldTile, 3)).forEach(t => { this.clearCell(t.cell()); }); if (event.unit.isActive()) { bfs(event.unit.tile(), dist(event.unit.tile(), 2)) - .forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255)); } if (event.unit.isActive()) { bfs(event.unit.tile(), dist(event.unit.tile(), 1)) - .forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255)); } } private handleBoatEvent(event: UnitEvent) { + const rel = this.relationship(event.unit) if (!this.boatToTrail.has(event.unit)) { this.boatToTrail.set(event.unit, new Set()); } @@ -142,30 +189,36 @@ export class UnitLayer implements Layer { this.clearCell(t.cell()); }); if (event.unit.isActive()) { - try { - bfs(event.unit.tile(), dist(event.unit.tile(), 4)).forEach( - t => { - if (trail.has(t)) { - this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 150); - } - } - ); - } catch { - consolex.log('uh oh') + for (const t of trail) { + this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 150); } bfs(event.unit.tile(), dist(event.unit.tile(), 2)) - .forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.borderColor(event.unit.owner().info()), 255)); bfs(event.unit.tile(), dist(event.unit.tile(), 1)) - .forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.unit.owner().info()), 255)); + .forEach(t => this.paintCell(t.cell(), rel, this.theme.territoryColor(event.unit.owner().info()), 255)); } else { trail.forEach(t => this.clearCell(t.cell())); this.boatToTrail.delete(event.unit); } } - paintCell(cell: Cell, color: Colord, alpha: number) { + paintCell(cell: Cell, relationship: Relationship, color: Colord, alpha: number) { this.clearCell(cell) - this.context.fillStyle = color.alpha(alpha / 255).toRgbString(); + if (this.alternateView) { + switch (relationship) { + case Relationship.Self: + this.context.fillStyle = this.theme.selfColor().toRgbString() + break + case Relationship.Ally: + this.context.fillStyle = this.theme.allyColor().toRgbString() + break + case Relationship.Enemy: + this.context.fillStyle = this.theme.enemyColor().toRgbString() + break + } + } else { + this.context.fillStyle = color.alpha(alpha / 255).toRgbString(); + } this.context.fillRect(cell.x, cell.y, 1, 1); } diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index d8aa1e034..a1d55659e 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -84,5 +84,9 @@ export interface Theme { backgroundColor(): Colord; falloutColor(): Colord font(): string; + // unit color for alternate view + selfColor(): Colord + allyColor(): Colord + enemyColor(): Colord } diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 9b472ef3b..1ad7819a8 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -25,9 +25,9 @@ export const devConfig = new class extends DefaultConfig { lobbyLifetime(): number { return 10 * 1000 } - // tradeShipSpawnRate(): number { - // return 10 - // } + tradeShipSpawnRate(): number { + return 10 + } boatMaxDistance(): number { return 5000 } diff --git a/src/core/configuration/PastelTheme.ts b/src/core/configuration/PastelTheme.ts index 40cd994d8..9b3ef29ec 100644 --- a/src/core/configuration/PastelTheme.ts +++ b/src/core/configuration/PastelTheme.ts @@ -122,6 +122,11 @@ export const pastelTheme = new class implements Theme { colord({ r: 170, g: 150, b: 170 }) // Dusty Rose ]; + private _selfColor = colord({ r: 0, g: 255, b: 0 }) + private _allyColor = colord({ r: 255, g: 255, b: 0 }) + private _enemyColor = colord({ r: 255, g: 0, b: 0 }) + + playerInfoColor(id: PlayerID): Colord { return colord({ r: 50, g: 50, b: 50 }) } @@ -199,4 +204,14 @@ export const pastelTheme = new class implements Theme { font(): string { return "Overpass, sans-serif"; } + + selfColor(): Colord { + return this._selfColor + } + allyColor(): Colord { + return this._allyColor + } + enemyColor(): Colord { + return this._enemyColor + } } \ No newline at end of file