perf(ui): switch UI layers to wall-time tick intervals (#3025)

## Description:

Preparatory change for the upcoming “unbounded worker” work: 
decouple expensive UI layer updates from game tick frequency by moving
UI ticking to wall-clock intervals. This reduces redundant UI work when
the simulation runs faster than real time (notably replays /
singleplayer at speed > 1) while keeping the UI responsive and
predictable.

## Changes:

- Add optional `Layer.getTickIntervalMs()` and enforce it in
`GameRenderer.tick()` using wall-clock time.
- Convert key UI layers from tick-modulus gating to fixed intervals:
  - `ControlPanel`: 100ms
  - `GameRightSidebar`: 250ms
  - `MainRadialMenu`: 500ms
  - `Leaderboard`, `NameLayer`, `ReplayPanel`, `TeamStats`: 1000ms


## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

## Please put your Discord username so you can be contacted if a bug or
regression is found:

DISCORD_USERNAME
This commit is contained in:
scamiv
2026-01-26 05:14:55 +01:00
committed by GitHub
parent de3794313d
commit 0bfad91c04
9 changed files with 90 additions and 46 deletions
+14 -12
View File
@@ -33,6 +33,10 @@ export class MainRadialMenu extends LitElement implements Layer {
private clickedTile: TileRef | null = null;
getTickIntervalMs() {
return 500;
}
constructor(
private eventBus: EventBus,
private game: GameView,
@@ -156,18 +160,16 @@ export class MainRadialMenu extends LitElement implements Layer {
async tick() {
if (!this.radialMenu.isMenuVisible() || this.clickedTile === null) return;
if (this.game.ticks() % 5 === 0) {
this.game
.myPlayer()!
.actions(this.clickedTile)
.then((actions) => {
this.updatePlayerActions(
this.game.myPlayer()!,
actions,
this.clickedTile!,
);
});
}
this.game
.myPlayer()!
.actions(this.clickedTile)
.then((actions) => {
this.updatePlayerActions(
this.game.myPlayer()!,
actions,
this.clickedTile!,
);
});
}
renderLayer(context: CanvasRenderingContext2D) {