8) Build a Physics Game (Pro)
Goal: build a playable physics scene with a grounded jump, a rotating crate, a goal, and collision filtering.
License: this tutorial requires the Pro GamePhysics feature.
Step 1: Create the World and Static Ground
Dim world As Integer
Dim ground As Integer
world = CreatePhysicsWorld(0.0, 900.0)
ground = CreatePhysicsBox(world, 400, 570, 800, 60, True)
SetBodyFriction(ground, 0.9)
SetBodyRestitution(ground, 0.0)
Positive Y gravity points downward. Body positions are centers, so a ground centered at Y 570 with height 60 reaches the bottom of a 600-pixel screen.
Step 2: Add a Controllable Body
Dim player As Integer
player = CreatePhysicsBox(world, 120, 120, 36, 48, False)
SetBodyFriction(player, 0.7)
SetBodyRestitution(player, 0.0)
SetBodyRotationLocked(player, True)
Rotation locking is useful for platform-game characters. The body still collides normally but will not tip over from contact impulses.
Step 3: Preserve Vertical Velocity While Moving
Dim horizontalSpeed As Double
horizontalSpeed = 0.0
If KeyDown(KEY_LEFT) Then
horizontalSpeed = -220.0
End If
If KeyDown(KEY_RIGHT) Then
horizontalSpeed = 220.0
End If
SetBodyVelocity( _
player, _
horizontalSpeed, _
BodyVelocityY(player) _
)
Replacing only the X component keeps gravity and jumping in control of the Y component.
Step 4: Identify the Body Under the Player
Dim grounded As Boolean
Dim contactIndex As Integer
Dim otherBody As Integer
grounded = False
For contactIndex = 0 To BodyCollisionCount(player) - 1
otherBody = BodyCollisionOther(player, contactIndex)
If otherBody = ground Then
grounded = True
End If
Next contactIndex
If grounded And KeyHit(KEY_SPACE) Then
SetBodyVelocity(player, BodyVelocityX(player), -430.0)
End If
Checking the other handle answers “what am I touching?” and prevents jumping merely because the player touched an unrelated body.
Step 5: Allow Other Bodies to Rotate
Dim crate As Integer
crate = CreatePhysicsBox(world, 440, 180, 64, 64, False)
SetBodyFriction(crate, 0.65)
SetBodyRestitution(crate, 0.05)
SetBodyRotation(crate, 12.0)
The crate can rotate naturally. While rendering, use BodyRotation with the draw-state transform so its visual shape stays aligned with its collision shape.
Step 6: Filter Collision Categories
Const CATEGORY_PLAYER As Integer = 1
Const CATEGORY_WORLD As Integer = 2
Const CATEGORY_GOAL As Integer = 4
Const CATEGORY_CRATE As Integer = 8
SetBodyCollisionFilter( _
player, CATEGORY_PLAYER, _
CATEGORY_WORLD + CATEGORY_GOAL + CATEGORY_CRATE _
)
SetBodyCollisionFilter( _
ground, CATEGORY_WORLD, _
CATEGORY_PLAYER + CATEGORY_CRATE _
)
Each body declares what it is and what it accepts. Distinct power-of-two category flags can be combined by addition.
Step 7: Advance Physics Before Rendering It
UpdatePhysics(world, FrameDelta())
PushDrawState()
SetDrawOffset(BodyX(crate), BodyY(crate))
SetDrawRotation(BodyRotation(crate))
DrawFilledRect(-32, -32, 64, 64)
PopDrawState()
UpdatePhysics uses an internal fixed 120 Hz accumulator. Call it once per game frame with FrameDelta(); do not write your own substep loop around it.
Checkpoint: Reach the Goal
Const CATEGORY_PLAYER As Integer = 1
Const CATEGORY_WORLD As Integer = 2
Const CATEGORY_GOAL As Integer = 4
Const CATEGORY_CRATE As Integer = 8
Graphics(800, 600, False)
SetClsColor(10, 15, 26)
Dim fontRef As Integer
Dim world As Integer
Dim player As Integer
Dim ground As Integer
Dim crate As Integer
Dim goal As Integer
Dim horizontalSpeed As Double
Dim grounded As Boolean
Dim reachedGoal As Boolean
Dim running As Boolean
Dim i As Integer
Dim otherBody As Integer
fontRef = LoadFont("", 18)
world = CreatePhysicsWorld(0.0, 900.0)
ground = CreatePhysicsBox(world, 400, 570, 800, 60, True)
player = CreatePhysicsBox(world, 100, 180, 36, 48, False)
crate = CreatePhysicsBox(world, 410, 180, 64, 64, False)
goal = CreatePhysicsCircle(world, 720, 510, 24, True)
running = True
SetBodyFriction(ground, 0.9)
SetBodyFriction(player, 0.7)
SetBodyFriction(crate, 0.65)
SetBodyRestitution(player, 0.0)
SetBodyRestitution(crate, 0.05)
SetBodyRotationLocked(player, True)
SetBodyRotation(crate, 12.0)
SetBodyCollisionFilter(player, CATEGORY_PLAYER, _
CATEGORY_WORLD + CATEGORY_GOAL + CATEGORY_CRATE)
SetBodyCollisionFilter(ground, CATEGORY_WORLD, _
CATEGORY_PLAYER + CATEGORY_CRATE)
SetBodyCollisionFilter(crate, CATEGORY_CRATE, _
CATEGORY_PLAYER + CATEGORY_WORLD + CATEGORY_CRATE)
SetBodyCollisionFilter(goal, CATEGORY_GOAL, CATEGORY_PLAYER)
Do
horizontalSpeed = 0.0
If KeyDown(KEY_LEFT) Then
horizontalSpeed = -220.0
End If
If KeyDown(KEY_RIGHT) Then
horizontalSpeed = 220.0
End If
SetBodyVelocity(player, horizontalSpeed, BodyVelocityY(player))
grounded = False
For i = 0 To BodyCollisionCount(player) - 1
otherBody = BodyCollisionOther(player, i)
If otherBody = ground Then
grounded = True
End If
If otherBody = goal Then
reachedGoal = True
End If
Next i
If grounded And KeyHit(KEY_SPACE) Then
SetBodyVelocity(player, BodyVelocityX(player), -430.0)
End If
UpdatePhysics(world, FrameDelta())
Cls()
SetDrawColor(75, 100, 140)
DrawFilledRect(0, 540, 800, 60)
SetDrawColor(255, 185, 65)
PushDrawState()
SetDrawOffset(BodyX(crate), BodyY(crate))
SetDrawRotation(BodyRotation(crate))
DrawFilledRect(-32, -32, 64, 64)
PopDrawState()
SetDrawColor(80, 220, 120)
DrawCircle(BodyX(goal), BodyY(goal), 24, 32)
SetDrawColor(80, 200, 255)
DrawFilledRect(BodyX(player) - 18, BodyY(player) - 24, 36, 48)
SetTextColor(240, 244, 255)
If reachedGoal Then
DrawText(fontRef, 20, 20, "Goal reached! ESC exits.")
Else
DrawText(fontRef, 20, 20, "Arrows move, Space jumps. Reach the ring.")
End If
Flip()
If KeyHit(KEY_ESC) Then
running = False
End If
Loop Until Not running
FreePhysicsBody(goal)
FreePhysicsBody(crate)
FreePhysicsBody(player)
FreePhysicsBody(ground)
FreePhysicsWorld(world)
FreeFont(fontRef)
Stability and Performance Rules
- Use static bodies for terrain and objects that should not move.
- Use realistic sizes and velocities; extremely deep overlaps require stronger correction.
- Keep restitution near zero for resting stacks and increase it only for intentionally bouncy objects.
- Use collision masks to exclude pairs that can never interact.
- Let sleeping bodies rest. Avoid rewriting positions or velocities every frame unless gameplay requires it.
- Free destroyed bodies and worlds when leaving a level.
Try It Yourself
Add a sloped static platform with SetBodyRotation, toggle the crate between dynamic and static with SetBodyStatic, and make a second category that the player ignores.
Functions Introduced
CreatePhysicsWorld, CreatePhysicsBox, UpdatePhysics, SetBodyRotationLocked, BodyCollisionOther, and SetBodyCollisionFilter.
Navigation: Previous | Course outline | 2D Physics Guide