Show entities and time per area while playing in the Game View (#275)
A game that stutters gave no hint where the frame goes. The Game tab now has a Performance switch. It shows a small overlay in the top left corner of the Game View while a game runs: fps, the number of entities and the mean milliseconds per frame for each area, averaged over half a second like the fps counter. - src/editor/frameMeter.ts holds the pure rule. FrameMeter sums the areas per frame, closes a window every 0.5 s and formats the lines. - World.timeSystem times every system the world ticks. PlaySession maps the systems to Behaviors, Physics and Animation and sets the hook again after Load scene. - Animation has its own line. Counting the AnimationSystem under Behaviors would have skewed that number. - Drawing is the build of the game picture plus app.render(). It is main thread time only. The GPU work after it is not in the number, and app.render() draws the whole canvas including the panels. - Editor is the rest of the editor tick after the systems and the game picture: mirroring into the model, panels and console. - The overlay lets clicks through to the game. It shows dashes until the first window closes. The switch is off by default and is not saved. The released game (#266) runs without a meter. Tests: - Unit frame-meter: 9 passed. - Gate on melektaus-atx: 197 files, 2853 tests, CHECK EXIT 0. - e2e 59 on melektaus-atx: ALL PASSED, 18 checks (13 before, +5 in 59e with a real mouse on the switch). Run twice. - Three mutations were caught: the editor share not subtracting the systems (2 unit tests), systems running in pause not reported (1 unit test), the overlay getting no times (59e). - The e2e total of 1601 is computed (1596 + 5), not measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d471150efb
commit
77f4c2c1a3
13 files changed
+436
-5
No files matched your search
@@ -9,6 +9,7 @@ export {
|
||||
initRenderLoop,
|
||||
onFrame,
|
||||
isRendering,
|
||||
lastRenderTime,
|
||||
renderCount,
|
||||
requestRender,
|
||||
resetRenderLoop,
|
||||
|
||||
@@ -21,6 +21,7 @@ const WAKE_MS = 200;
|
||||
|
||||
let deadline = 0;
|
||||
let rendered = 0;
|
||||
let renderMs = 0;
|
||||
|
||||
/** Draw, and keep drawing for a moment. Cheap enough to call from every event. */
|
||||
export function requestRender(): void {
|
||||
@@ -37,6 +38,11 @@ export function renderCount(): number {
|
||||
return rendered;
|
||||
}
|
||||
|
||||
/** What `app.render()` took for the last frame drawn, in ms – the CPU side; the GPU works on after. */
|
||||
export function lastRenderTime(): number {
|
||||
return renderMs;
|
||||
}
|
||||
|
||||
/** Work put off to the next frame by `onFrame`, one entry per key. */
|
||||
let frameWork = new Map<string, () => void>();
|
||||
|
||||
@@ -109,7 +115,9 @@ export function initRenderLoop(app: Application): void {
|
||||
for (const fn of due.values()) fn();
|
||||
}
|
||||
rendered += 1;
|
||||
const start = performance.now();
|
||||
app.render();
|
||||
renderMs = performance.now() - start;
|
||||
// Taken first: a waiter that queues itself again must land in the next round, not this one.
|
||||
const waiters = frameWaiters;
|
||||
frameWaiters = [];
|
||||
@@ -125,6 +133,7 @@ export function initRenderLoop(app: Application): void {
|
||||
export function resetRenderLoop(): void {
|
||||
deadline = 0;
|
||||
rendered = 0;
|
||||
renderMs = 0;
|
||||
frameWaiters = [];
|
||||
frameWork = new Map();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user