create unit layer

This commit is contained in:
Evan
2024-11-09 13:32:25 -08:00
parent aea22f089c
commit 3ac8dbddc5
4 changed files with 123 additions and 42 deletions
+5 -4
View File
@@ -172,11 +172,12 @@
* rewrite EventsDisplay DONE 11/1/2024 * rewrite EventsDisplay DONE 11/1/2024
* update Mena NPC locations DONE 11/1/2024 * update Mena NPC locations DONE 11/1/2024
* create build menu DONE 11/3/2024 * create build menu DONE 11/3/2024
* add gold * add gold DONE 11/4/2024
* add troop/worker slider * add troop/worker slider DONE 11/4/2024
* add battleship * create Unit layer DONE 11/9/2024
* create Unit interface
* add destroyer
* NPC has relations * NPC has relations
* fix name rendering
* use twitter emojis * use twitter emojis
* private game shows how many players joined * private game shows how many players joined
* optimize sendBoat function * optimize sendBoat function
+2
View File
@@ -14,6 +14,7 @@ import { Leaderboard } from "./layers/Leaderboard";
import { ControlPanel } from "./layers/ControlPanel"; import { ControlPanel } from "./layers/ControlPanel";
import { UIState } from "./UIState"; import { UIState } from "./UIState";
import { BuildMenu } from "./layers/radial/BuildMenu"; import { BuildMenu } from "./layers/radial/BuildMenu";
import { UnitLayer } from "./layers/UnitLayer";
export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer { export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer {
@@ -61,6 +62,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
const layers: Layer[] = [ const layers: Layer[] = [
new TerrainLayer(game), new TerrainLayer(game),
new TerritoryLayer(game, eventBus), new TerritoryLayer(game, eventBus),
new UnitLayer(game, eventBus),
new NameLayer(game, game.config().theme(), transformHandler, clientID), new NameLayer(game, game.config().theme(), transformHandler, clientID),
new UILayer(eventBus, game, clientID, transformHandler), new UILayer(eventBus, game, clientID, transformHandler),
eventsDisplay, eventsDisplay,
+13 -38
View File
@@ -1,33 +1,33 @@
import {PriorityQueue} from "@datastructures-js/priority-queue"; import { PriorityQueue } from "@datastructures-js/priority-queue";
import {Boat, BoatEvent, Cell, Game, Player, Tile, TileEvent} from "../../../core/game/Game"; import { Cell, Game, Player, Tile, TileEvent } from "../../../core/game/Game";
import {PseudoRandom} from "../../../core/PseudoRandom"; import { PseudoRandom } from "../../../core/PseudoRandom";
import {Colord} from "colord"; import { Colord } from "colord";
import {bfs, dist} from "../../../core/Util"; import { bfs, dist } from "../../../core/Util";
import {Theme} from "../../../core/configuration/Config"; import { Theme } from "../../../core/configuration/Config";
import {Layer} from "./Layer"; import { Layer } from "./Layer";
import {TransformHandler} from "../TransformHandler"; import { TransformHandler } from "../TransformHandler";
import {EventBus} from "../../../core/EventBus"; import { EventBus } from "../../../core/EventBus";
export class TerritoryLayer implements Layer { export class TerritoryLayer implements Layer {
private canvas: HTMLCanvasElement private canvas: HTMLCanvasElement
private context: CanvasRenderingContext2D private context: CanvasRenderingContext2D
private imageData: ImageData private imageData: ImageData
private tileToRenderQueue: PriorityQueue<{tileEvent: TileEvent, lastUpdate: number}> = new PriorityQueue((a, b) => {return a.lastUpdate - b.lastUpdate}) private tileToRenderQueue: PriorityQueue<{ tileEvent: TileEvent, lastUpdate: number }> = new PriorityQueue((a, b) => { return a.lastUpdate - b.lastUpdate })
private random = new PseudoRandom(123) private random = new PseudoRandom(123)
private theme: Theme = null private theme: Theme = null
private boatToTrail = new Map<Boat, Set<Tile>>()
constructor(private game: Game, eventBus: EventBus) { constructor(private game: Game, eventBus: EventBus) {
this.theme = game.config().theme() this.theme = game.config().theme()
eventBus.on(TileEvent, e => this.tileUpdate(e)) eventBus.on(TileEvent, e => this.tileUpdate(e))
eventBus.on(BoatEvent, e => this.boatEvent(e))
} }
shouldTransform(): boolean { shouldTransform(): boolean {
return true return true
} }
tick() { tick() {
} }
@@ -62,31 +62,6 @@ export class TerritoryLayer implements Layer {
) )
} }
boatEvent(event: BoatEvent) {
if (!this.boatToTrail.has(event.boat)) {
this.boatToTrail.set(event.boat, new Set<Tile>())
}
const trail = this.boatToTrail.get(event.boat)
trail.add(event.oldTile)
bfs(event.oldTile, dist(event.oldTile, 3)).forEach(t => {
this.paintTerritory(t)
})
if (event.boat.isActive()) {
bfs(event.boat.tile(), dist(event.boat.tile(), 4)).forEach(
t => {
if (trail.has(t)) {
this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 150)
}
}
)
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().info()), 255))
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 180))
} else {
trail.forEach(t => this.paintTerritory(t))
this.boatToTrail.delete(event.boat)
}
}
renderTerritory() { renderTerritory() {
let numToRender = Math.floor(this.tileToRenderQueue.size() / 10) let numToRender = Math.floor(this.tileToRenderQueue.size() / 10)
if (numToRender == 0) { if (numToRender == 0) {
@@ -138,6 +113,6 @@ export class TerritoryLayer implements Layer {
} }
tileUpdate(event: TileEvent) { tileUpdate(event: TileEvent) {
this.tileToRenderQueue.push({tileEvent: event, lastUpdate: this.game.ticks() + this.random.nextFloat(0, .5)}) this.tileToRenderQueue.push({ tileEvent: event, lastUpdate: this.game.ticks() + this.random.nextFloat(0, .5) })
} }
} }
+103
View File
@@ -0,0 +1,103 @@
import { Colord } from "colord";
import { Theme } from "../../../core/configuration/Config";
import { Boat, BoatEvent, Cell, Game, Tile } from "../../../core/game/Game";
import { bfs, dist } from "../../../core/Util";
import { Layer } from "./Layer";
import { EventBus } from "../../../core/EventBus";
export class UnitLayer implements Layer {
private canvas: HTMLCanvasElement
private context: CanvasRenderingContext2D
private imageData: ImageData
private boatToTrail = new Map<Boat, Set<Tile>>()
private theme: Theme = null
constructor(private game: Game, private eventBus: EventBus) {
this.theme = game.config().theme()
}
shouldTransform(): boolean {
return true
}
tick() {
}
init(game: Game) {
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext("2d")
this.imageData = this.context.getImageData(0, 0, this.game.width(), this.game.height())
this.canvas.width = this.game.width();
this.canvas.height = this.game.height();
this.context.putImageData(this.imageData, 0, 0);
this.initImageData()
this.eventBus.on(BoatEvent, e => this.onBoatEvent(e))
}
initImageData() {
this.game.forEachTile((tile) => {
const index = (tile.cell().y * this.game.width()) + tile.cell().x
const offset = index * 4
this.imageData.data[offset + 3] = 0
})
}
renderLayer(context: CanvasRenderingContext2D) {
this.context.putImageData(this.imageData, 0, 0);
context.drawImage(
this.canvas,
-this.game.width() / 2,
-this.game.height() / 2,
this.game.width(),
this.game.height()
)
}
onBoatEvent(event: BoatEvent) {
if (!this.boatToTrail.has(event.boat)) {
this.boatToTrail.set(event.boat, new Set<Tile>())
}
const trail = this.boatToTrail.get(event.boat)
trail.add(event.oldTile)
bfs(event.oldTile, dist(event.oldTile, 3)).forEach(t => {
this.clearCell(t.cell())
})
if (event.boat.isActive()) {
bfs(event.boat.tile(), dist(event.boat.tile(), 4)).forEach(
t => {
if (trail.has(t)) {
this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 150)
}
}
)
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().info()), 255))
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().info()), 180))
} else {
trail.forEach(t => this.clearCell(t.cell()))
this.boatToTrail.delete(event.boat)
}
}
paintCell(cell: Cell, color: Colord, alpha: number) {
const index = (cell.y * this.game.width()) + cell.x
const offset = index * 4
this.imageData.data[offset] = color.rgba.r;
this.imageData.data[offset + 1] = color.rgba.g;
this.imageData.data[offset + 2] = color.rgba.b;
this.imageData.data[offset + 3] = alpha
}
clearCell(cell: Cell) {
const index = (cell.y * this.game.width()) + cell.x;
const offset = index * 4;
this.imageData.data[offset + 3] = 0; // Set alpha to 0 (fully transparent)
}
}