PhysicsAPI reference
Interface IPhysicsWorld2D
Namespace: MicroEngine.Physics
Assembly: MicroEngine.Physics.dll
Guide: Physics worlds
A 2D physics world: bodies owned by entities, shapes with collision layers, kinematic collide-and-slide moves, ray and overlap queries, sensors, and a step. The members below are the common contract every backend passes (one conformance suite); everything else is a declared capability (Capabilities), and a request that needs an undeclared one throws PhysicsCapabilityException without changing the world.
public interface IPhysicsWorld2DRemarks
The rules of the contract:
- Bodies and shapes. Static and kinematic bodies and axis-aligned box shapes are common; a shape is placed at its body's origin plus its offset. Ids are generation-checked: a stale id is never alive, and using one throws `InvalidOperationException`; destroying a body destroys its shapes.
- Layers. Two shapes collide only when each one's [Mask](/docs/api/microengine.physics.shapedescription/#MicroEngine_Physics_ShapeDescription_Mask) holds the other's [Category](/docs/api/microengine.physics.shapedescription/#MicroEngine_Physics_ShapeDescription_Category); a query or move sees a shape only when [Accepts](/docs/api/microengine.physics.queryfilter/#MicroEngine_Physics_QueryFilter_Accepts_System_UInt64_System_UInt64_) is true for it.
- Move moves a kinematic body's one non-sensor shape, an axis-aligned box (the common character shape; a capsule needs [Capsules](/docs/api/microengine.physics.physicscapabilities/)), by collide-and-slide against the non-sensor shapes the filter accepts: it never passes through a shape at the speeds the conformance suite tests, and a blocked axis stops while the others go on. It may stop short of a surface by a gap of at most [Skin](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_Skin), the tolerance the backend declares (0 on the tile backend). The body's contacts and its ground are in the [MoveResult](/docs/api/microengine.physics.moveresult/); a shape the box already overlaps when the move starts does not block it, so a body is never trapped.
- Queries. [RayCast](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_RayCast_System_Numerics_Vector2_System_Numerics_Vector2_MicroEngine_Physics_QueryFilter__MicroEngine_Physics_RayHit__) returns the closest hit; [Overlap](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_Overlap_MicroEngine_RectF__MicroEngine_Physics_QueryFilter__System_Span_MicroEngine_Physics_ShapeId__) is exact (shapes that truly overlap the area, not their bounding boxes; sharing an edge is not overlapping). Both leave sensors out unless the filter includes them.
- Sensors. A sensor reports the non-sensor shapes of kinematic and dynamic bodies that begin or stop overlapping it, when the layers of both accept each other and the visitor has [SensorEvents](/docs/api/microengine.physics.shapedescription/#MicroEngine_Physics_ShapeDescription_SensorEvents) (the default). Sensors do not see other sensors or static shapes.
- Events are buffered per step. [Step](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_Step_System_Single_) computes [SensorEvents](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_SensorEvents) and [ContactEvents](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_ContactEvents) from the poses at its end (moves made before it count in it); they stay readable until the next step, in an order that depends only on the world's history. Contact events only come from pairs with a dynamic body. Destroying a shape ends its pairs with an exit or end event at the next step.
- No managed callbacks during [Step](/docs/api/microengine.physics.iphysicsworld2d/#MicroEngine_Physics_IPhysicsWorld2D_Step_System_Single_). Per-shape rules (one-way platforms) are shape flags the backend implements itself; games read events after the step.
- Stepping. [PhysicsModule](/docs/api/microengine.physics.physicsmodule/) steps registered worlds in the kernel's
FramePhase.Physics, inside the fixed step, and writes body poses to their owners' transforms; the scene world interpolates them for drawing. - Determinism. The same backend build gives identical results on every target for the same calls (native backends are built with floating-point contraction off and step on one thread). Nothing is promised between two backends, or between two versions of a backend's physics library: they differ from the first step.
A world is not thread-safe.
Properties
Backend
The backend’s name, for messages (“tiles”, “box2d”).
string Backend { get; }Property Value
Bodies
The live bodies, in creation order (a destroyed body leaves its place).
ReadOnlySpan<BodyId> Bodies { get; }Property Value
Capabilities
What the backend offers beyond the common contract.
PhysicsCapabilities Capabilities { get; }Property Value
ContactEvents
The contacts that began or ended in the latest step (pairs with a dynamic body only).
ReadOnlySpan<ContactEvent> ContactEvents { get; }Property Value
SensorEvents
The sensor entries and exits of the latest step.
ReadOnlySpan<SensorEvent> SensorEvents { get; }Property Value
Skin
The largest gap Move may leave between a body and the surface that stopped it or that it rests on, in world units: 0 when resting is exact.
float Skin { get; }Property Value
StepCount
How many times Step ran.
long StepCount { get; }Property Value
Up
The world’s up direction (unit length): it tells ground from ceilings and which side of a one-way platform stops bodies.
Vector2 Up { get; }Property Value
Methods
AddShape(BodyId, in ShapeDescription)
Attaches a shape to body.
ShapeId AddShape(BodyId body, in ShapeDescription shape)Parameters
body BodyId
shape ShapeDescription
Returns
Exceptions
The description needs an undeclared capability.
The description is invalid (Validate).
The body id is stale.
BodyOf(ShapeId)
The body shape is attached to.
BodyId BodyOf(ShapeId shape)Parameters
shape ShapeId
Returns
Exceptions
The id is stale.
CreateBody(EntityId, in BodyDescription)
Creates a body owned by owner.
BodyId CreateBody(EntityId owner, in BodyDescription body)Parameters
owner EntityId
body BodyDescription
Returns
Exceptions
The description needs an undeclared capability.
The description is invalid (Validate).
DescriptionOf(ShapeId)
The description shape was added with (its geometry is relative to its body’s origin).
ShapeDescription DescriptionOf(ShapeId shape)Parameters
shape ShapeId
Returns
Exceptions
The id is stale.
The backend does not declare ShapeInspection.
DestroyBody(BodyId)
Destroys the body and its shapes; nothing for a stale or none id. Their sensor pairs end at the next step.
void DestroyBody(BodyId body)Parameters
body BodyId
IsAlive(BodyId)
Whether body exists.
bool IsAlive(BodyId body)Parameters
body BodyId
Returns
IsAlive(ShapeId)
Whether shape exists.
bool IsAlive(ShapeId shape)Parameters
shape ShapeId
Returns
KindOf(BodyId)
How body moves.
BodyKind KindOf(BodyId body)Parameters
body BodyId
Returns
Exceptions
The id is stale.
Move(BodyId, Vector2, in QueryFilter)
Moves a kinematic body by delta with collide-and-slide against the shapes
filter accepts (see the rules); a body that pushes bodies
(PushesBodies) is not blocked and moves the bodies in its way instead.
MoveResult Move(BodyId body, Vector2 delta, in QueryFilter filter = default)Parameters
body BodyId
delta Vector2
filter QueryFilter
Returns
Exceptions
The id is stale, the body is not kinematic, or it has no single non-sensor shape the backend can move.
delta is not finite.
Overlap(in RectF, in QueryFilter, Span<ShapeId>)
Writes into results the shapes that truly overlap area, in an order that
depends only on the world’s history, and returns how many overlap (which may exceed the span’s length: only the
first ones are written).
int Overlap(in RectF area, in QueryFilter filter, Span<ShapeId> results)Parameters
area RectF
filter QueryFilter
Returns
OwnerOf(BodyId)
The entity that owns body.
EntityId OwnerOf(BodyId body)Parameters
body BodyId
Returns
Exceptions
The id is stale.
PositionOf(BodyId)
The body’s origin.
Vector2 PositionOf(BodyId body)Parameters
body BodyId
Returns
Exceptions
The id is stale.
RayCast(Vector2, Vector2, in QueryFilter, out RayHit)
The closest shape the segment from from to to enters; a shape holding from is not hit.
bool RayCast(Vector2 from, Vector2 to, in QueryFilter filter, out RayHit hit)Parameters
from Vector2
to Vector2
filter QueryFilter
hit RayHit
Returns
Exceptions
A point is not finite.
RemoveShape(ShapeId)
Removes a shape; nothing for a stale or none id. Its sensor pairs end at the next step.
void RemoveShape(ShapeId shape)Parameters
shape ShapeId
RotationOf(BodyId)
The body’s angle in radians (0 for backends without Rotation).
float RotationOf(BodyId body)Parameters
body BodyId
Returns
Exceptions
The id is stale.
SetPosition(BodyId, Vector2)
Teleports the body: no collision, no pushing; sensor events follow at the next step.
void SetPosition(BodyId body, Vector2 position)Parameters
body BodyId
position Vector2
Exceptions
The id is stale.
The position is not finite.
SetVelocity(BodyId, Vector2)
Sets a dynamic body’s velocity.
void SetVelocity(BodyId body, Vector2 velocity)Parameters
body BodyId
velocity Vector2
Exceptions
The backend does not declare DynamicBodies.
ShapesOf(BodyId, Span<ShapeId>)
Writes the live shapes of body, in the order they were added, into results
and returns how many it has (which may exceed the span’s length: only the first ones are written).
int ShapesOf(BodyId body, Span<ShapeId> results)Parameters
body BodyId
Returns
Exceptions
The body is stale.
The backend does not declare ShapeInspection.
Step(float)
Advances the world by dt seconds: dynamic bodies move, and the events of this step replace the
previous ones. No game code runs during it.
void Step(float dt)Parameters
dt float
Exceptions
dt is negative or not finite.
VelocityOf(BodyId)
A dynamic body’s velocity.
Vector2 VelocityOf(BodyId body)Parameters
body BodyId
Returns
Exceptions
The backend does not declare DynamicBodies.