Add stats overlay with cursor position, TPS, and colony info
This commit is contained in:
parent
d91b5a9b5e
commit
9f958089c0
4 changed files with 102 additions and 2 deletions
19
index.html
19
index.html
|
|
@ -45,6 +45,25 @@
|
|||
width: 65px;
|
||||
}
|
||||
|
||||
#stats {
|
||||
font-family: monospace;
|
||||
color: #777;
|
||||
padding: 8px 12px;
|
||||
font-size: 11px;
|
||||
line-height: 1.8;
|
||||
border-bottom: 1px solid #1a1a1a;
|
||||
}
|
||||
|
||||
#stats .label {
|
||||
display: inline-block;
|
||||
width: 65px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
#stats .value {
|
||||
color: #c43c3c;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
width: calc(100% - 16px);
|
||||
margin: 12px 8px;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import Config from "./Config";
|
||||
import GUI from "./GUI";
|
||||
import Renderer from "./Renderer";
|
||||
import StatsOverlay from "./StatsOverlay";
|
||||
import AntsComputeScene from "./scenes/AntsComputeScene";
|
||||
import AntsDiscretizeScene from "./scenes/AntsDiscretizeScene";
|
||||
import DrawScene from "./scenes/DrawScene";
|
||||
|
|
@ -25,6 +26,7 @@ export default new (class App {
|
|||
);
|
||||
private scenes!: SceneCollection;
|
||||
private gui: GUI = new GUI();
|
||||
private statsOverlay: StatsOverlay = new StatsOverlay();
|
||||
private renderLoop = (time: number): void => this.render(time);
|
||||
private lastTime: number = 0;
|
||||
private queuedSimSteps: number = 0;
|
||||
|
|
@ -82,6 +84,7 @@ export default new (class App {
|
|||
}
|
||||
|
||||
this.renderer.renderSimulation(this.scenes);
|
||||
this.statsOverlay.recordTick();
|
||||
}
|
||||
|
||||
private render(time: number) {
|
||||
|
|
@ -105,6 +108,11 @@ export default new (class App {
|
|||
|
||||
this.renderer.renderToScreen(this.scenes);
|
||||
|
||||
this.statsOverlay.update(
|
||||
this.scenes.screen.pointerPosition,
|
||||
this.renderer.colonyStatsData,
|
||||
);
|
||||
|
||||
this.lastTime = time;
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { WebGLRenderTarget } from "three";
|
||||
import * as THREE from "three";
|
||||
import type { SceneCollection } from "./App";
|
||||
import ColonyStats from "./ColonyStats";
|
||||
import ColonyStats, { type ColonyStatsData } from "./ColonyStats";
|
||||
import Config from "./Config";
|
||||
import {
|
||||
MAT_AIR,
|
||||
|
|
@ -406,6 +406,10 @@ export default class Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
public get colonyStatsData(): ColonyStatsData {
|
||||
return this.colonyStats.data;
|
||||
}
|
||||
|
||||
static convertNumberToFloatString(n: number): string {
|
||||
return n.toFixed(8);
|
||||
}
|
||||
|
|
|
|||
69
src/StatsOverlay.ts
Normal file
69
src/StatsOverlay.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import type { ColonyStatsData } from "./ColonyStats";
|
||||
import Config from "./Config";
|
||||
|
||||
export default class StatsOverlay {
|
||||
private el: HTMLElement;
|
||||
private cursorEl: HTMLElement;
|
||||
private tpsEl: HTMLElement;
|
||||
private antsEl: HTMLElement;
|
||||
private carryingEl: HTMLElement;
|
||||
|
||||
private tickTimestamps: number[] = [];
|
||||
|
||||
constructor() {
|
||||
this.el = document.createElement("div");
|
||||
this.el.id = "stats";
|
||||
|
||||
// insert after #info
|
||||
// biome-ignore lint/style/noNonNullAssertion: #info exists in index.html
|
||||
const info = document.getElementById("info")!;
|
||||
info.after(this.el);
|
||||
|
||||
this.cursorEl = this.addLine("cursor");
|
||||
this.tpsEl = this.addLine("tps");
|
||||
this.antsEl = this.addLine("ants");
|
||||
this.carryingEl = this.addLine("carrying");
|
||||
}
|
||||
|
||||
private addLine(label: string): HTMLElement {
|
||||
const line = document.createElement("div");
|
||||
line.innerHTML = `<span class="label">${label}</span><span class="value">—</span>`;
|
||||
this.el.appendChild(line);
|
||||
// biome-ignore lint/style/noNonNullAssertion: .value span created by innerHTML above
|
||||
return line.querySelector(".value")!;
|
||||
}
|
||||
|
||||
public recordTick(): void {
|
||||
const now = performance.now();
|
||||
this.tickTimestamps.push(now);
|
||||
// keep last 60 timestamps for averaging
|
||||
if (this.tickTimestamps.length > 60) {
|
||||
this.tickTimestamps.shift();
|
||||
}
|
||||
}
|
||||
|
||||
public update(
|
||||
pointerPosition: { x: number; y: number },
|
||||
colonyStats: ColonyStatsData,
|
||||
): void {
|
||||
const gridX = Math.floor(pointerPosition.x * Config.worldSize);
|
||||
const gridY = Math.floor(pointerPosition.y * Config.worldSize);
|
||||
this.cursorEl.textContent = `${gridX}, ${gridY}`;
|
||||
|
||||
// tps from tick timestamps
|
||||
if (this.tickTimestamps.length >= 2) {
|
||||
const span =
|
||||
this.tickTimestamps[this.tickTimestamps.length - 1] -
|
||||
this.tickTimestamps[0];
|
||||
const tps =
|
||||
span > 0 ? ((this.tickTimestamps.length - 1) / span) * 1000 : 0;
|
||||
this.tpsEl.textContent = `${Math.round(tps)}`;
|
||||
}
|
||||
|
||||
this.antsEl.textContent = `${colonyStats.totalAnts}`;
|
||||
const carrying = Math.round(
|
||||
colonyStats.foragerRatio * colonyStats.totalAnts,
|
||||
);
|
||||
this.carryingEl.textContent = `${carrying}`;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue