The Scoreboard Was Eating My Level
Every rim in Get Buckets VR carries a small scoreboard that yaws to face the player, so you can read your makes and time remaining from wherever you are standing. It is a nice bit of readability and I did not think about it again after building it, until a Challenge level playtest came back with a note I could not immediately explain: “I can’t see the target from the left corner.”
The target in question was a floating ring, not the main hoop, placed a little behind and to the side of the rim as part of a trick shot line. From most standing positions it read fine. From a narrow band over near the left wall, the scoreboard had yawed around to face the player and its body was sitting directly between their eyes and the ring.
Why eyeballing it was not going to work
My first instinct was to walk the room in the editor, stand in a few spots, and see if anything looked blocked. That works for one level. It does not work for fifteen levels, each of which can get its rim rig nudged during later passes, because the scoreboard’s blocking angle depends on the interaction of three things that all move independently: where the player’s head actually is, the target’s position, and the scoreboard’s current yaw, which itself depends on where the player’s head is. A fix that looks clean from three sampled spots can still have a bad wedge you never happened to stand in.
I needed a way to check the whole space, not a few points in it, and I needed it to be repeatable every time a level’s geometry changed.
The check
I built a validation pass that treats this as pure geometry instead of a play session. First, a sample grid of points across the target’s visible face, not just its center, since a target can be nine tenths visible and still read as fully blocked if a single occluder sits over the middle. Then a set of roughly 200 simulated head positions spread across the area of the playspace a real player could plausibly occupy while shooting, including the corners and near the walls where the original bug lived.
For every one of those head positions, the pass computes the scoreboard’s yaw the same way the runtime does, since it is always facing the current viewpoint, builds the scoreboard’s oriented bounding box at that orientation, and ray tests every sample point on the target against it. If a ray from the head position to a target sample point intersects the OBB, that sample point counts as blocked from that head position. A head position fails the check once too high a fraction of the target’s sample points are blocked, rather than at the first blocked ray, so a target that is barely clipped at a grazing angle does not get flagged as unusable.
Running this against the level immediately reproduced the reported dead zone, and mapping the failing head positions back into the room made the shape of the problem obvious: a wedge near the left wall where the scoreboard’s yawed orientation lined up almost exactly with the sightline to the ring. From there the fix was mechanical, clamping how far the scoreboard is allowed to yaw and nudging its mount offset, then rerunning the pass until zero head positions failed.
Why this earns its keep
A solo project does not have a QA team re-walking every level after every rig tweak. What it can have is a script that takes a few seconds to tell you whether any of your 200 simulated vantage points can no longer see what they are supposed to see. I now run this pass on every Challenge level after any change to rim, scoreboard, or target placement, and it has already caught two more near misses before they made it into a playtest build. Geometry does not get tired of being checked. Playtesters, reasonably, do.