Add stomps or gold, then try 60 Hz with a slow map to see captures skipped without losing counts. Each gain reaches take() once after a delay; clear drops pending reads.
The GPU detects collisions and kills, while the CPU updates scores, plays sounds and restarts levels. A kernel can’t call CPU code. Reporting event details requires a queue, but a count is often enough. Kernels increment a counter for each event kind. The CPU reads the change a frame or two later.
Counts named events on the GPU and reads them back to the CPU. Kernels add hits, kills, pickups
or other events. The CPU receives the increases a frame or two later. Requires at least one
name, with no duplicates. Throws if names are invalid, hz is not finite and above 0, or
staging is not an integer above 0.
@injects ― per-instance add, for kernels piped with it
@binds ― 1 storage: add, the counters
@owns ― a buffer, a readback: the counters; the readback copies them at hz
@records ― capture after the passes that add; clear before them, whenever the counting starts
again; in frame mode, capture clears after copying.
@param ― names one counter each
@returns ― a set of counters you destroy
create(
constroot:TgpuRoot
root,['stomps','hurts'],{
Options.hz?: number |undefined
Reads counters for take and latest this many times per second on average. Default 30.
Returns the increase in each counter since the last take, or the captured counts in frame
mode. Returns each read once, then undefined until the next read arrives. Reuses one object
and updates it in place.
take();// what each gained since the last take, or undefined
Records commands for submission after the recorder returns. submit() replaces this encoder.
Read it at each call instead of keeping it, and let the frame submit it.
Copies counters when a read is due, then clears them in frame mode. Record after the passes
that add events.
capture(
frame:frames.Frame
frame);// after the passes that add
});
add.stomps(amount) adds atomically, from any thread of any kernel piped with contacts.inject(). The amount can vary, such as a kill’s reward of 1, 4 or 1000 gold.
capture copies counters at hz, 30 times per second by default. It uses a readback with staging buffers, 3 by default, and skips a capture while all are mapping. The platformer reads at 60 Hz, so the hero bounces a frame or two after a stomp.
take() returns each counter’s increase since the last take, once per completed read, and undefined between reads. latest holds totals since the last clear. Each reuses an object and updates it in place. Copy a result to keep it.
Counters only increase, so late or repeated reads lose no events. The next difference includes them. Differences use u32 arithmetic and remain correct across a wrap at 2^32.
Use { per: 'frame' } to count objects in a frame, such as the stampede’s skinned horses and cards. capture copies when a read is due and clears counters every frame. latest and take() then return one frame’s counts. Call capture every frame, after the passes that count.
clear(encoder) sets every counter to 0 in your encoder and drops the reads made before it, so the next gains count from the clear. Record it before the passes that add, as at a restart:
Resets all counters to 0 in the caller's encoder. Record before the passes that add events.
clear(
frame:frames.Frame
frame.
Frame.encoder: TgpuCommandEncoder
Records commands for submission after the recorder returns. submit() replaces this encoder.
Read it at each call instead of keeping it, and let the frame submit it.
encoder);
let restarting:boolean
restarting=false;
// ... the passes that add, then tally.capture(frame)
});
Read latest to display totals such as enemies spawned, slain or through the gate. The platformer keeps its counters across restarts and ignores damage for 1.5 s, longer than a read takes to complete.
Counters omit event details such as location. Handle immediate effects on the GPU, such as squashing a critter or emitting dust. Let the CPU react to the count.
Per-item thresholds need separate counters. The fish tank uses its own counter array to count bites per pellet and decide on the GPU when each is eaten.