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:
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}");
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,OnSleepandOnWake. ACollisioncarries the other body and shape, the normal, the contact points, the normal impulse and the approach speed. - Polled events:
world.Eventsis every event of the last step andworld.GetEvents(kind)the slice of one kind. Both are spans, valid until the nextStep, 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.