mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 10:21:27 +00:00
make territory translucent
This commit is contained in:
@@ -3,10 +3,8 @@ import {Cell, Game, PlayerEvent, Tile, TileEvent, Player, Execution, BoatEvent}
|
||||
import {Theme} from "../../core/configuration/Config";
|
||||
import {DragEvent, ZoomEvent} from "../InputHandler";
|
||||
import {NameRenderer} from "./NameRenderer";
|
||||
import {bfs, dist, manhattanDist} from "../../core/Util";
|
||||
import {PseudoRandom} from "../../core/PseudoRandom";
|
||||
import {TerrainRenderer} from "./TerrainRenderer";
|
||||
import {PriorityQueue} from "@datastructures-js/priority-queue";
|
||||
import {TerritoryRenderer} from "./TerritoryRenderer";
|
||||
|
||||
export class GameRenderer {
|
||||
private territoryCanvas: HTMLCanvasElement
|
||||
@@ -21,15 +19,14 @@ export class GameRenderer {
|
||||
private context: CanvasRenderingContext2D
|
||||
|
||||
private nameRenderer: NameRenderer;
|
||||
private territoryRenderer: TerritoryRenderer;
|
||||
|
||||
private theme: Theme
|
||||
|
||||
private random = new PseudoRandom(123)
|
||||
|
||||
private tileToRenderQueue: PriorityQueue<{tileEvent: TileEvent, lastUpdate: number}> = new PriorityQueue((a, b) => {return a.lastUpdate - b.lastUpdate})
|
||||
|
||||
constructor(private gs: Game, private terrainRenderer: TerrainRenderer) {
|
||||
this.theme = gs.config().theme()
|
||||
this.nameRenderer = new NameRenderer(gs, this.theme)
|
||||
this.territoryRenderer = new TerritoryRenderer(gs)
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -45,6 +42,7 @@ export class GameRenderer {
|
||||
|
||||
this.nameRenderer.initialize()
|
||||
this.terrainRenderer.init()
|
||||
this.territoryRenderer.init()
|
||||
|
||||
|
||||
document.body.appendChild(this.canvas);
|
||||
@@ -56,6 +54,8 @@ export class GameRenderer {
|
||||
this.territoryCanvas.width = this.gs.width();
|
||||
this.territoryCanvas.height = this.gs.height();
|
||||
this.territoryContext = this.territoryCanvas.getContext('2d')
|
||||
this.territoryContext.globalAlpha = 0.4;
|
||||
|
||||
|
||||
requestAnimationFrame(() => this.renderGame());
|
||||
}
|
||||
@@ -67,7 +67,6 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
renderGame() {
|
||||
|
||||
// Set background
|
||||
this.context.fillStyle = this.theme.backgroundColor().toHex();
|
||||
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
@@ -94,15 +93,7 @@ export class GameRenderer {
|
||||
);
|
||||
|
||||
this.terrainRenderer.draw(this.context)
|
||||
this.renderTerritory()
|
||||
|
||||
this.context.drawImage(
|
||||
this.territoryCanvas,
|
||||
-this.gs.width() / 2,
|
||||
-this.gs.height() / 2,
|
||||
this.gs.width(),
|
||||
this.gs.height()
|
||||
)
|
||||
this.territoryRenderer.draw(this.context)
|
||||
|
||||
const [upperLeft, bottomRight] = this.boundingRect()
|
||||
this.nameRenderer.render(this.context, this.scale, upperLeft, bottomRight)
|
||||
@@ -111,24 +102,9 @@ export class GameRenderer {
|
||||
|
||||
this.renderUIBar()
|
||||
|
||||
|
||||
requestAnimationFrame(() => this.renderGame());
|
||||
}
|
||||
|
||||
renderTerritory() {
|
||||
let numToRender = Math.floor(this.tileToRenderQueue.size() / 10)
|
||||
if (numToRender == 0) {
|
||||
numToRender = this.tileToRenderQueue.size()
|
||||
}
|
||||
|
||||
while (numToRender > 0) {
|
||||
numToRender--
|
||||
const event = this.tileToRenderQueue.pop().tileEvent
|
||||
this.paintTerritory(event.tile)
|
||||
event.tile.neighbors().forEach(t => this.paintTerritory(t))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
renderUIBar() {
|
||||
if (!this.gs.inSpawnPhase()) {
|
||||
@@ -153,18 +129,15 @@ export class GameRenderer {
|
||||
}
|
||||
|
||||
tileUpdate(event: TileEvent) {
|
||||
this.tileToRenderQueue.push({tileEvent: event, lastUpdate: this.gs.ticks() + this.random.nextFloat(0, .5)})
|
||||
this.territoryRenderer.tileUpdate(event)
|
||||
// this.tileToRenderQueue.push({tileEvent: event, lastUpdate: this.gs.ticks() + this.random.nextFloat(0, .5)})
|
||||
}
|
||||
|
||||
playerEvent(event: PlayerEvent) {
|
||||
}
|
||||
|
||||
boatEvent(event: BoatEvent) {
|
||||
bfs(event.oldTile, dist(event.oldTile, 2)).forEach(t => this.paintTerritory(t))
|
||||
if (event.boat.isActive()) {
|
||||
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().id())))
|
||||
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().id())))
|
||||
}
|
||||
this.territoryRenderer.boatEvent(event)
|
||||
}
|
||||
|
||||
resize(width: number, height: number): void {
|
||||
@@ -172,22 +145,24 @@ export class GameRenderer {
|
||||
this.canvas.height = Math.ceil(height / window.devicePixelRatio);
|
||||
}
|
||||
|
||||
paintTerritory(tile: Tile) {
|
||||
if (!tile.hasOwner()) {
|
||||
this.clearCell(tile.cell())
|
||||
return
|
||||
}
|
||||
// this.territoryContext.clearRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
if (tile.isBorder()) {
|
||||
this.territoryContext.fillStyle = this.theme.borderColor(tile.owner().id()).toRgbString()
|
||||
} else {
|
||||
this.territoryContext.fillStyle = this.theme.territoryColor(tile.owner().id()).toRgbString()
|
||||
}
|
||||
this.territoryContext.fillRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
}
|
||||
// paintTerritory(tile: Tile) {
|
||||
// this.clearCell(tile.cell())
|
||||
// // if (!tile.hasOwner()) {
|
||||
// // this.clearCell(tile.cell())
|
||||
// // return
|
||||
// // }
|
||||
// // this.territoryContext.clearRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
// if (tile.isBorder()) {
|
||||
// this.territoryContext.fillStyle = this.theme.borderColor(tile.owner().id()).toRgbString()
|
||||
// } else {
|
||||
// this.territoryContext.fillStyle = this.theme.territoryColor(tile.owner().id()).alpha(100).toHex()
|
||||
// }
|
||||
// this.territoryContext.fillRect(tile.cell().x, tile.cell().y, 1, 1);
|
||||
// }
|
||||
|
||||
paintCell(cell: Cell, color: Colord) {
|
||||
this.territoryContext.fillStyle = color.toRgbString()
|
||||
color = color.alpha(10) // Assign the result back to color
|
||||
this.territoryContext.fillStyle = color.toHslString()
|
||||
this.territoryContext.fillRect(cell.x, cell.y, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {inherits} from "util"
|
||||
import {Game} from "../../core/Game";
|
||||
import {throws} from "assert";
|
||||
|
||||
export class TerrainRenderer {
|
||||
private canvas: HTMLCanvasElement
|
||||
@@ -15,11 +16,9 @@ export class TerrainRenderer {
|
||||
|
||||
this.imageData = this.context.getImageData(0, 0, this.game.width(), this.game.height())
|
||||
this.initImageData()
|
||||
this.canvas = document.createElement('canvas');
|
||||
const backgroundCtx = this.canvas.getContext('2d');
|
||||
this.canvas.width = this.game.width();
|
||||
this.canvas.height = this.game.height();
|
||||
backgroundCtx.putImageData(this.imageData, 0, 0);
|
||||
this.context.putImageData(this.imageData, 0, 0);
|
||||
}
|
||||
|
||||
initImageData() {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import {PriorityQueue} from "@datastructures-js/priority-queue";
|
||||
import {BoatEvent, Cell, Game, Tile, TileEvent} from "../../core/Game";
|
||||
import {PseudoRandom} from "../../core/PseudoRandom";
|
||||
import {Colord} from "colord";
|
||||
import {bfs, dist} from "../../core/Util";
|
||||
import {Theme} from "../../core/configuration/Config";
|
||||
|
||||
export class TerritoryRenderer {
|
||||
private canvas: HTMLCanvasElement
|
||||
private context: CanvasRenderingContext2D
|
||||
private imageData: ImageData
|
||||
|
||||
private tileToRenderQueue: PriorityQueue<{tileEvent: TileEvent, lastUpdate: number}> = new PriorityQueue((a, b) => {return a.lastUpdate - b.lastUpdate})
|
||||
private random = new PseudoRandom(123)
|
||||
private theme: Theme = null
|
||||
|
||||
|
||||
|
||||
constructor(private game: Game) {
|
||||
this.theme = game.config().theme()
|
||||
}
|
||||
|
||||
init() {
|
||||
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);
|
||||
}
|
||||
|
||||
draw(context: CanvasRenderingContext2D) {
|
||||
this.renderTerritory()
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
||||
boatEvent(event: BoatEvent) {
|
||||
bfs(event.oldTile, dist(event.oldTile, 2)).forEach(t => this.clearCell(t.cell()))
|
||||
if (event.boat.isActive()) {
|
||||
bfs(event.boat.tile(), dist(event.boat.tile(), 2)).forEach(t => this.paintCell(t.cell(), this.theme.borderColor(event.boat.owner().id()), 255))
|
||||
bfs(event.boat.tile(), dist(event.boat.tile(), 1)).forEach(t => this.paintCell(t.cell(), this.theme.territoryColor(event.boat.owner().id()), 255))
|
||||
}
|
||||
}
|
||||
|
||||
renderTerritory() {
|
||||
let numToRender = Math.floor(this.tileToRenderQueue.size() / 10)
|
||||
if (numToRender == 0) {
|
||||
numToRender = this.tileToRenderQueue.size()
|
||||
}
|
||||
|
||||
while (numToRender > 0) {
|
||||
numToRender--
|
||||
const event = this.tileToRenderQueue.pop().tileEvent
|
||||
this.paintTerritory(event.tile)
|
||||
event.tile.neighbors().forEach(t => this.paintTerritory(t))
|
||||
}
|
||||
}
|
||||
|
||||
paintTerritory(tile: Tile) {
|
||||
if (tile.isBorder()) {
|
||||
this.paintCell(
|
||||
tile.cell(),
|
||||
this.theme.borderColor(tile.owner().id()),
|
||||
255
|
||||
)
|
||||
} else {
|
||||
this.paintCell(
|
||||
tile.cell(),
|
||||
this.theme.territoryColor(tile.owner().id()),
|
||||
75
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
tileUpdate(event: TileEvent) {
|
||||
this.tileToRenderQueue.push({tileEvent: event, lastUpdate: this.game.ticks() + this.random.nextFloat(0, .5)})
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ export const devConfig = new class extends DefaultConfig {
|
||||
}
|
||||
|
||||
numBots(): number {
|
||||
return 0
|
||||
return 250
|
||||
}
|
||||
|
||||
startTroops(playerInfo: PlayerInfo): number {
|
||||
|
||||
@@ -90,10 +90,37 @@ export const pastelTheme = new class implements Theme {
|
||||
if (tile.isShore()) {
|
||||
return this.shore
|
||||
}
|
||||
// let mag = Math.min(tile.magnitude() + 4, 15)
|
||||
// if (mag < 3) {
|
||||
// mag = 0
|
||||
// }
|
||||
let mag = tile.magnitude()
|
||||
// if (mag < 3) {
|
||||
// return colord({
|
||||
// r: 0,
|
||||
// g: 0,
|
||||
// b: 0
|
||||
// })
|
||||
// }
|
||||
|
||||
if (mag < 2) {
|
||||
mag = 0
|
||||
}
|
||||
|
||||
// else if (mag < 5) {
|
||||
// mag = 1
|
||||
// } else if (mag < 8) {
|
||||
// mag = 10
|
||||
// } else {
|
||||
// mag = 15
|
||||
// }
|
||||
|
||||
const delta = 8 * mag
|
||||
|
||||
return colord({
|
||||
r: 174 + 5 * tile.magnitude(),
|
||||
g: 163 + 5 * tile.magnitude(),
|
||||
b: 128 + 5 * tile.magnitude()
|
||||
r: 190 + delta,
|
||||
g: 193 + delta,
|
||||
b: 138 + delta
|
||||
})
|
||||
} else {
|
||||
const w = this.water.rgba
|
||||
|
||||
Reference in New Issue
Block a user