Skip to content

Scoring shots

An impact event arrives a moment after the trigger breaks: the device detects the shot by its recoil, and by then it may already have moved. To score a shot, use the aimpoint from the moment the trigger broke, not the latest one.

Finding the aimpoint at the moment of the shot A timeline. Tracking events arrive about every 10 ms. The trigger breaks; the impact is detected a little later, after the shot delay. Subtract the shot delay from the impact's timestamp and use the tracking event closest to that time. time tracking events, about every 10 ms trigger breaks impact event its timestamp shot delay (set per device) use the event closest to timestamp − shot delay

Each device has a shot delay: how long after the trigger breaks its recoil is detected, in milliseconds. Users set it per device in Odyssey Desktop; your app reads it with get_shot_delay.

  1. Keep the recent tracking events of each device. The SDK’s TrackingHistory does this: create one per device and push every tracking event into it. It keeps the last N events.
  2. When an impact arrives, subtract the device’s shot delay, converted to microseconds, from the impact’s timestamp.
  3. Ask the history for the event closest to that time with get_closest, and score its aimpoint.

Impacts from accessories, such as Bluetooth magazines, have no device clock: their timestamp is 0xFFFFFFFF. For those, start from the latest tracking event’s timestamp instead of the impact’s.

const uint AccessoryTimestamp = 0xFFFFFFFF;
// The device timestamp at which the trigger broke.
static uint ShotTimestamp(Ohc.uniffi.TrackingHistory history, uint impactTs, ushort shotDelayMs)
{
if (impactTs == AccessoryTimestamp && history.Latest() is { } latest)
impactTs = latest.Timestamp;
return unchecked(impactTs - (uint)shotDelayMs * 1000u);
}
// For each device: var history = new Ohc.uniffi.TrackingHistory(1000), then
// history.Push(tracking) for every tracking event, and
// var shotDelayMs = await client.GetShotDelay(device). On an impact:
var shot = history.GetClosest(ShotTimestamp(history, impact.V1.Timestamp, shotDelayMs));
if (shot != null)
Console.WriteLine($"hit at ({shot.Aimpoint.X:F3}, {shot.Aimpoint.Y:F3})");

The Python sample shows this in a complete program.

Shot delays change when users adjust them in Odyssey Desktop. To keep yours current, subscribe to them with subscribe_shot_delay.