import type * as THREE from "three"; export interface ColonyStatsData { foragerRatio: number; // fraction of ants currently carrying food totalAnts: number; // total ant count } export default class ColonyStats { private buffer: Float32Array; private statsData: ColonyStatsData = { foragerRatio: 0, totalAnts: 0, }; constructor() { this.buffer = new Float32Array(0); } public update( renderer: THREE.WebGLRenderer, antTarget: THREE.WebGLRenderTarget, ): ColonyStatsData { const width = antTarget.width; const height = antTarget.height; const pixelCount = width * height; // resize buffer if needed if (this.buffer.length !== pixelCount * 4) { this.buffer = new Float32Array(pixelCount * 4); } renderer.readRenderTargetPixels( antTarget, 0, 0, width, height, this.buffer, ); let carryingCount = 0; let activeAnts = 0; for (let i = 0; i < pixelCount; i++) { const posX = this.buffer[i * 4]; const posY = this.buffer[i * 4 + 1]; const w = this.buffer[i * 4 + 3]; // alpha = packed state // skip uninitialized ants (both coordinates at origin) if (posX === 0 && posY === 0) continue; activeAnts++; const isCarrying = Math.trunc(w) & 1; if (isCarrying) carryingCount++; } this.statsData.totalAnts = activeAnts; this.statsData.foragerRatio = activeAnts > 0 ? carryingCount / activeAnts : 0; return this.statsData; } public get data(): ColonyStatsData { return this.statsData; } }