improved lag issues and added terrain effects

This commit is contained in:
Restart2008
2026-02-19 17:15:15 -08:00
parent 0ba13e5ed3
commit 511547f72d
2 changed files with 84 additions and 22 deletions
+47 -17
View File
@@ -37,6 +37,7 @@ export class TerritoryLayer implements Layer {
private tileToRenderQueue: PriorityQueue<{
tile: TileRef;
lastUpdate: number;
redrawNeighbors: boolean;
}> = new PriorityQueue((a, b) => {
return a.lastUpdate - b.lastUpdate;
});
@@ -534,8 +535,10 @@ export class TerritoryLayer implements Layer {
const tile = entry.tile;
this.paintTerritory(tile);
for (const neighbor of this.game.neighbors(tile)) {
this.paintTerritory(neighbor, true);
if (entry.redrawNeighbors) {
for (const neighbor of this.game.neighbors(tile)) {
this.paintTerritory(neighbor, true);
}
}
}
}
@@ -596,7 +599,9 @@ export class TerritoryLayer implements Layer {
}
const urbanization = this.game.getUrbanization(tile);
let color = owner.territoryColor(tile);
let r = owner.baseR;
let g = owner.baseG;
let b = owner.baseB;
let alpha = 150;
if (urbanization.density > 0.05) {
@@ -604,15 +609,22 @@ export class TerritoryLayer implements Layer {
alpha = 160 + Math.min(85, urbanization.density * 70);
// Lightness Gradient: Rural (Low density) is lighter, Urban (High density) is darker/richer.
// We interpolate between a "rural" shade and an "urban" shade of the player's color.
const ruralShade = color.lighten(0.15).desaturate(0.05);
const urbanShade = color.darken(0.15).saturate(0.2);
// Fast RGB interpolation using pre-calculated shades
const mixRatio = Math.min(1, urbanization.density);
color = ruralShade.mix(urbanShade, mixRatio);
const invRatio = 1 - mixRatio;
r = (owner.ruralR * invRatio + owner.urbanR * mixRatio) | 0;
g = (owner.ruralG * invRatio + owner.urbanG * mixRatio) | 0;
b = (owner.ruralB * invRatio + owner.urbanB * mixRatio) | 0;
} else {
// Apply pattern if not in urban area
const color = owner.territoryColor(tile);
r = color.rgba.r;
g = color.rgba.g;
b = color.rgba.b;
}
this.paintTile(this.imageData, tile, color, alpha);
this.paintTileRaw(this.imageData, tile, r, g, b, alpha);
}
}
@@ -639,13 +651,30 @@ export class TerritoryLayer implements Layer {
}
paintTile(imageData: ImageData, tile: TileRef, color: Colord, alpha: number) {
const offset = tile * 4;
imageData.data[offset] = color.rgba.r;
imageData.data[offset + 1] = color.rgba.g;
imageData.data[offset + 2] = color.rgba.b;
imageData.data[offset + 3] = alpha;
this.paintTileRaw(
imageData,
tile,
color.rgba.r,
color.rgba.g,
color.rgba.b,
alpha,
);
}
paintTileRaw(
imageData: ImageData,
tile: TileRef,
r: number,
g: number,
b: number,
alpha: number,
) {
const offset = tile * 4;
imageData.data[offset] = r;
imageData.data[offset + 1] = g;
imageData.data[offset + 2] = b;
imageData.data[offset + 3] = alpha;
}
clearTile(tile: TileRef) {
const offset = tile * 4;
this.imageData.data[offset + 3] = 0; // Set alpha to 0 (fully transparent)
@@ -657,15 +686,16 @@ export class TerritoryLayer implements Layer {
this.alternativeImageData.data[offset + 3] = 0; // Set alpha to 0 (fully transparent)
}
enqueueTile(tile: TileRef) {
enqueueTile(tile: TileRef, redrawNeighbors: boolean = true) {
this.tileToRenderQueue.push({
tile: tile,
lastUpdate: this.game.ticks() + this.random.nextFloat(0, 0.5),
redrawNeighbors: redrawNeighbors,
});
}
enqueueCityArea(city: UnitView) {
const radius = Math.ceil(city.areaRadius() * 1.4 + 2);
const radius = Math.ceil(city.areaRadius() * 1.6 + 2);
const tile = city.tile();
const cx = this.game.x(tile);
const cy = this.game.y(tile);
@@ -673,7 +703,7 @@ export class TerritoryLayer implements Layer {
for (let x = cx - radius; x <= cx + radius; x++) {
for (let y = cy - radius; y <= cy + radius; y++) {
if (this.game.isValidCoord(x, y)) {
this.enqueueTile(this.game.ref(x, y));
this.enqueueTile(this.game.ref(x, y), false);
}
}
}
+37 -5
View File
@@ -227,6 +227,17 @@ export class PlayerView {
private _urbanizationBuildingColor: Colord;
private _urbanizationCoreColor: Colord;
// Optimized RGB values for urbanization shading
public readonly ruralR: number;
public readonly ruralG: number;
public readonly ruralB: number;
public readonly urbanR: number;
public readonly urbanG: number;
public readonly urbanB: number;
public readonly baseR: number;
public readonly baseG: number;
public readonly baseB: number;
constructor(
private game: GameView,
public data: PlayerUpdate,
@@ -272,6 +283,21 @@ export class PlayerView {
this._territoryColor = defaultTerritoryColor;
}
const rural = this._territoryColor.lighten(0.15).desaturate(0.05).rgba;
this.ruralR = rural.r;
this.ruralG = rural.g;
this.ruralB = rural.b;
const urban = this._territoryColor.darken(0.15).saturate(0.2).rgba;
this.urbanR = urban.r;
this.urbanG = urban.g;
this.urbanB = urban.b;
const base = this._territoryColor.rgba;
this.baseR = base.r;
this.baseG = base.g;
this.baseB = base.b;
this._structureColors = this.game
.config()
.theme()
@@ -1013,7 +1039,7 @@ export class GameView implements GameMap {
const cached = this.urbanizationCache.get(tile);
if (cached) return cached;
const nearby = this.nearbyUnits(tile, 40, UnitType.City);
const nearby = this.nearbyUnits(tile, 60, UnitType.City);
if (nearby.length === 0) {
const result = { density: 0 };
this.urbanizationCache.set(tile, result);
@@ -1026,6 +1052,7 @@ export class GameView implements GameMap {
const tileOwnerID = this.ownerID(tile);
const tx = this.x(tile);
const ty = this.y(tile);
const terrainMag = this.magnitude(tile);
for (let i = 0; i < nearby.length; i++) {
const { unit, distSquared } = nearby[i];
@@ -1042,15 +1069,20 @@ export class GameView implements GameMap {
const dx = tx - ux;
const dy = ty - uy;
// Faster angle approximation or just use atan2 (it's called once per nearby city)
const angle = Math.atan2(dy, dx);
const uid = unit.id();
// Simplified noise with fewer sin calls
// More complex noise to ensure irregular shapes even at high city levels
const noise =
1 + 0.18 * Math.sin(angle * 3 + uid) + 0.12 * Math.sin(angle * 5 - uid);
1 +
0.22 * Math.sin(angle * 3 + uid) +
0.15 * Math.sin(angle * 7 - uid * 1.3) +
0.08 * Math.sin(angle * 13 + uid * 0.7);
const irregularRadius = radius * noise;
// Terrain expansion logic: cities expand easily in plains, poorly in mountains.
// Magnitude 0-30 scale. We penalize distance based on terrain difficulty.
const terrainFactor = Math.max(0.2, 1.0 - Math.min(terrainMag, 25) / 35);
const irregularRadius = radius * noise * terrainFactor;
if (dist <= irregularRadius) {
// Linear fade is faster than Math.pow