← Documentation Home

2D Game Physics Guide (Pro)

Back to System Functions

The native physics API is designed for straightforward platform, arcade, puzzle, and top-down games. It supports dynamic and static circles and oriented boxes, including angular motion and rotation locking.

Quick start

world = CreatePhysicsWorld(0, 980)
player = CreatePhysicsBox(world, 100, 100, 32, 48, False)
ground = CreatePhysicsBox(world, 320, 460, 640, 40, True)
SetBodyFriction ground, 0.9
SetBodyRotation ground, -5
SetBodyRotationLocked player, True

Do
    If KeyDown(KEY_LEFT) Then SetBodyVelocity player, -180, BodyVelocityY(player)
    If KeyDown(KEY_RIGHT) Then SetBodyVelocity player, 180, BodyVelocityY(player)

    UpdatePhysics world, FrameDelta()
    PushDrawState()
    SetDrawOffset BodyX(player), BodyY(player)
    SetDrawRotation BodyRotation(player)
    DrawImage playerImage, 0, 0
    PopDrawState()
    Flip()
Loop

Simulation model

UpdatePhysics converts variable frame time into fixed 120 Hz steps. Each step integrates linear and angular velocity, uses X-axis sweep and prune with cached two-dimensional bounds, and generates exact circle/oriented-box contacts once. Eight cached sequential-impulse passes then resolve normal, friction, and angular velocity without repeating broad-phase or contact-clipping work. Penetration correction is applied once per step. Catch-up is limited to four fixed steps so a slow frame cannot create an unbounded simulation backlog.

Coordinates and sizes are integer-based at the BASIC boundary. Linear velocity, rotation, and angular velocity use Double values. Rotation APIs use degrees and angular velocity uses degrees per second.

Rotation and static bodies

SetBodyRotation sets an angle immediately. SetBodyAngularVelocity starts or changes spin. Use BodyRotation while drawing so the visual and collision shape remain aligned.

SetBodyRotationLocked(body, True) stops spin and prevents collision impulses from rotating that body. SetBodyStatic can switch an existing body between dynamic and immovable without recreating its handle. Making a body static clears its linear and angular velocity.

Low-speed contacts suppress restitution and apply contact damping so tiny gravity impacts do not continually re-energize a resting pile. Bodies that remain below the linear and angular sleep thresholds for half a second stop integrating and are treated as immovable by low-speed neighbors. Position, velocity, rotation, angular-velocity, static-state, and filter setters wake a dynamic body immediately; a sufficiently fast impact also wakes it.

Collision reporting

BodyIsColliding is the simplest grounded or impact check. BodyCollisionCount(body) gives that body's current contact count, and BodyCollisionOther(body, index) returns the other body handle for a zero-based contact index. The world-level PhysicsCollisionCount, PhysicsCollisionBodyA, and PhysicsCollisionBodyB functions remain useful when processing every pair centrally.

For i = 0 To BodyCollisionCount(player) - 1
    other = BodyCollisionOther(player, i)
    If other = goal Then reachedGoal = True
Next

Collision filter flags

SetBodyCollisionFilter(body, categoryFlags, maskFlags) assigns the categories a body belongs to and the categories it accepts. A pair collides only when each body's mask includes at least one category flag from the other body. New bodies use category 1 and mask -1, which accepts every bit.

Const CATEGORY_PLAYER As Integer = 1
Const CATEGORY_ENEMY As Integer = 2
Const CATEGORY_PICKUP As Integer = 4

SetBodyCollisionFilter player, CATEGORY_PLAYER, CATEGORY_ENEMY + CATEGORY_PICKUP
SetBodyCollisionFilter enemy, CATEGORY_ENEMY, CATEGORY_PLAYER

Filtered pairs produce no physical response and do not appear in body-level or world-level collision results.