Recursive AI

Events and sensors

All onephysics recipes

React to collisions, impacts, sleep and sensor overlaps in OnePhysics, with handlers or polled events, in an order that is the same on every machine.

A ball falls through a sensor zone onto the ground:

C#
using RecursiveAI.OneMath;
using RecursiveAI.OnePhysics;
using RecursiveAI.OnePhysics.Physics2D;
 
var world = new PhysicsWorld2D(new WorldOptions2D { Events = EventMask.Default | EventMask.ContactHit });
var ground = world.AddBox(new Vector2F(20, 1), at: new Vector2D(0, -0.5), type: BodyType.Static);
 
var ball = world.AddCircle(0.5f, at: new Vector2D(0, 6));
ball.OnCollisionEnter += c => Console.WriteLine($"enter: ball touches {(c.Other == ground ? "ground" : c.Other.ToString())}");
ball.OnCollisionHit += c => Console.WriteLine($"hit: landed at {c.ApproachSpeed:F3} m/s");
ball.OnSleep += b => Console.WriteLine($"the ball fell asleep");
 
// A sensor: reports overlaps, never pushes.
var zone = world.CreateBody(new BodyDef { Type = BodyType.Static, Position = new Vector2D(0, 3) });
world.CreateBox(zone, new Vector2F(4, 1), def: new ShapeDef { IsSensor = true });
zone.OnTriggerEnter += t => Console.WriteLine("trigger: something entered the zone");
zone.OnTriggerExit += t => Console.WriteLine("trigger: it left the zone");
 
int begins = 0;
for (int i = 0; i < 300; i++)
{
    world.Step(1f / 60);
    begins += world.GetEvents(EventKind.ContactBegin).Length;   // polled: a span, valid until the next step
}
Console.WriteLine($"polled ContactBegin events: {begins}");
Text
trigger: something entered the zone
trigger: it left the zone
enter: ball touches ground
hit: landed at 10.464 m/s
the ball fell asleep
polled ContactBegin events: 1

Two ways to listen

  • Handlers on a body: OnCollisionEnter, OnCollisionStay, OnCollisionExit, OnCollisionHit, OnTriggerEnter, OnTriggerExit, OnSleep and OnWake. A Collision carries the other body and shape, the normal, the contact points, the normal impulse and the approach speed.
  • Polled events: world.Events is every event of the last step and world.GetEvents(kind) the slice of one kind. Both are spans, valid until the next Step, and allocate nothing. Prefer them in rollback code.

WorldOptions2D.Events chooses what is recorded: ContactHit (impacts with their speed) and ContactPersist are off by default, and a kind that is off costs nothing.

Order

Events are sorted after each step, first by kind (ContactBegin, ContactPersist, ContactEnd, SensorEnter, SensorExit, JointBreak, Sleep, Wake, ContactHit) and then by the slots of the bodies and shapes, and handlers run in that order: first for body A of a pair, then body B. The same inputs give the same list on every platform and thread count. Details in events.