mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:11:54 +00:00
create unit layer
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user