diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index d14f4448c..8ded3ee6f 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -40,6 +40,7 @@ export class UnitLayer implements Layer { private unitTrailContext: CanvasRenderingContext2D; private unitToTrail = new Map(); + private pendingTrailClears: UnitView[] = []; private theme: Theme; @@ -381,6 +382,7 @@ export class UnitLayer implements Layer { // otherwise the sprite of a unit can be drawn on top of another unit this.clearUnitsCells(unitsToUpdate); this.drawUnitsCells(unitsToUpdate); + this.flushTrailClears(); } } @@ -546,19 +548,33 @@ export class UnitLayer implements Layer { } } - private clearTrail(unit: UnitView) { - const trail = this.unitToTrail.get(unit) ?? []; - const rel = this.relationship(unit); - for (const t of trail) { - this.clearCell(this.game.x(t), this.game.y(t), this.unitTrailContext); - } - this.unitToTrail.delete(unit); + private flushTrailClears() { + if (this.pendingTrailClears.length === 0) return; - // Repaint overlapping trails - const trailSet = new Set(trail); + const clearedTiles = new Set(); + for (const unit of this.pendingTrailClears) { + const trail = this.unitToTrail.get(unit); + if (trail) { + for (const t of trail) { + if (!clearedTiles.has(t)) { + this.clearCell( + this.game.x(t), + this.game.y(t), + this.unitTrailContext, + ); + clearedTiles.add(t); + } + } + this.unitToTrail.delete(unit); + } + } + this.pendingTrailClears = []; + + // Single repaint pass for all remaining units for (const [other, trail] of this.unitToTrail) { + const rel = this.relationship(other); for (const t of trail) { - if (trailSet.has(t)) { + if (clearedTiles.has(t)) { this.paintCell( this.game.x(t), this.game.y(t), @@ -609,7 +625,7 @@ export class UnitLayer implements Layer { ); this.drawSprite(unit); if (!unit.isActive()) { - this.clearTrail(unit); + this.pendingTrailClears.push(unit); } } @@ -652,7 +668,7 @@ export class UnitLayer implements Layer { this.drawSprite(unit); if (!unit.isActive()) { - this.clearTrail(unit); + this.pendingTrailClears.push(unit); } }