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.
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.
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.
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.
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.
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.
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.
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.
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)
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.
CreatePhysicsWorld, CreatePhysicsBox, UpdatePhysics, SetBodyRotationLocked, BodyCollisionOther, and SetBodyCollisionFilter.
Navigation: Previous | Course outline | 2D Physics Guide