Quick answer: Create a player sprite with the Platform behavior, build your level geometry with a Tilemap object that has the Solid behavior, add smooth camera scrolling with lerp, and layer in collectibles, enemies, and polish effects. Construct 3’s built-in Platform behavior handles gravity, jumping, and slope movement out of the box, so you can focus on designing levels and gameplay.
Platformers are one of the most natural game types to build in Construct 3. The engine ships with a dedicated Platform behavior that handles gravity, jumping, acceleration, and collision with solid ground — all without writing a single line of code. In this guide, we will walk through building a complete platformer from your first sprite to polished gameplay, covering the techniques that separate a prototype from a game that feels good to play.
Setting Up the Player Character
Start by creating a new project in Construct 3 and setting the layout size to something larger than the viewport — 4096 x 1024 is a good starting point for a side-scrolling level. The viewport (window size) can stay at the default 640 x 480 or whatever resolution you prefer.
Create a Sprite object for your player. Add two behaviors to it: Platform and Scroll To. The Platform behavior gives the player gravity, jumping, and left/right movement with default keyboard controls. The Scroll To behavior makes the camera follow the player automatically.
Configure the Platform behavior properties to get the right feel for your game:
// Platform behavior properties for a responsive platformer
// Set these in the Properties panel after selecting the player
// Movement
// Max Speed: 300 (pixels per second)
// Acceleration: 1500 (how quickly the player reaches max speed)
// Deceleration: 1200 (how quickly the player stops)
// Jumping
// Jump Strength: 650 (initial upward velocity)
// Gravity: 1500 (downward acceleration)
// Max Fall Speed: 1500 (terminal velocity)
// Slopes
// Max Floor Slope: 50 (degrees, default is fine for most games)
For animations, set up at least four animation sequences on your player sprite: Idle, Run, Jump, and Fall. Then use events to switch between them based on the Platform behavior’s state:
// Player animation state machine
Player: Platform is moving
Player: Platform is on floor
→ Player: Set animation to "Run"
Player: Platform is NOT moving
Player: Platform is on floor
→ Player: Set animation to "Idle"
Player: Platform is falling
→ Player: Set animation to "Fall"
Player: Platform is jumping
→ Player: Set animation to "Jump"
// Flip sprite to face movement direction
Player: Platform is moving right
→ Player: Set mirrored to Not mirrored
Player: Platform is moving left
→ Player: Set mirrored to Mirrored
Building Levels with Tilemaps
For level geometry, use the Tilemap object rather than placing individual sprites. A Tilemap renders and handles collision as a single object regardless of how many tiles it contains, which is far more efficient than hundreds of separate sprite instances.
Create a Tilemap object and import your tileset image. A standard tile size is 32x32 or 16x16 pixels. In the Tilemap bar at the bottom of the layout editor, you can paint tiles directly onto the layout. Add the Solid behavior to the Tilemap so the Platform behavior recognizes it as ground.
Each tile type needs its own collision polygon. Open the Tilemap collision editor and set polygons for each tile:
// Tilemap collision setup
// - Full block tiles: full rectangle polygon (0,0 to 32,32)
// - Slope tiles: triangle polygon matching the slope angle
// - One-way platforms: use a separate Tilemap with Jump-thru behavior
// - Decorative tiles: no collision polygon (leave empty)
// For slopes, use these polygon points (32x32 tile):
// 45-degree slope rising left to right:
// (0, 32), (32, 0), (32, 32)
// 45-degree slope rising right to left:
// (0, 0), (32, 32), (0, 32)
A good practice is to use multiple Tilemap layers: one for background decoration (no collision), one for the solid ground geometry, and optionally one for foreground decoration that renders in front of the player. Use the Z-order or layer ordering to control which elements appear in front of or behind the player.
Smooth Camera Scrolling
The built-in Scroll To behavior works but feels rigid. For a more polished feel, remove Scroll To and implement smooth camera follow manually using the lerp function:
// Smooth camera follow with lerp
// Add these events (no Scroll To behavior needed)
System: Every tick
→ System: Set scroll X to
lerp(ScrollX, Player.X, 8 * dt)
→ System: Set scroll Y to
lerp(ScrollY, Player.Y, 8 * dt)
// The third parameter controls smoothness:
// - Higher values (10-15) = tighter, more responsive
// - Lower values (3-5) = looser, more cinematic
// Multiply by dt to keep it framerate-independent
To prevent the camera from scrolling past the level boundaries, clamp the scroll position:
// Clamp camera to level bounds
System: Every tick
→ System: Set scroll X to
clamp(lerp(ScrollX, Player.X, 8*dt), ViewportWidth/2, LayoutWidth - ViewportWidth/2)
→ System: Set scroll Y to
clamp(lerp(ScrollY, Player.Y, 8*dt), ViewportHeight/2, LayoutHeight - ViewportHeight/2)
For extra polish, add a look-ahead offset so the camera leads slightly in the direction the player is moving. This gives the player more visibility of upcoming obstacles:
// Camera look-ahead
// Create an instance variable "CameraOffsetX" on the Player
Player: Platform is moving right
→ Player: Set CameraOffsetX to
lerp(Player.CameraOffsetX, 80, 4 * dt)
Player: Platform is moving left
→ Player: Set CameraOffsetX to
lerp(Player.CameraOffsetX, -80, 4 * dt)
// Then use Player.X + Player.CameraOffsetX as the scroll target X
Collectibles and Enemies
Create a Sprite object for your collectible (coin, gem, etc.) and place instances throughout the level. Detection is simple — check for overlap between the player and the collectible:
// Collectible pickup
// Create a global variable "Score" set to 0
Player: On collision with Coin
→ Coin: Destroy
→ System: Add 1 to Score
→ Audio: Play "coin-pickup" not looping
// Add a bounce animation for flair
// Give the Coin object the Sine behavior:
// Movement: Vertical, Period: 1.5, Magnitude: 6
For enemies, create an enemy sprite with the Platform behavior but set Default Controls to No. This gives the enemy gravity and floor detection without responding to keyboard input. Then use events to control its movement:
// Basic patrol enemy
// Create instance variables on Enemy:
// Direction (number, default 1)
// Speed (number, default 100)
System: Every tick
→ Enemy: Simulate Platform pressing
Right if Enemy.Direction = 1
→ Enemy: Simulate Platform pressing
Left if Enemy.Direction = -1
// Turn around at edges (place invisible EdgeMarker sprites)
Enemy: On collision with EdgeMarker
→ Enemy: Set Direction to Enemy.Direction * -1
→ Enemy: Set mirrored to
(Enemy.Direction = 1 ? "Not mirrored" : "Mirrored")
// Stomp to kill (player lands on top)
Player: On collision with Enemy
Player: Is falling
Player: Compare Y < Enemy.Y - Enemy.Height/4
→ Enemy: Destroy
→ Player: Set Platform vector Y to -400
// Bounce the player upward after stomp
// Player hit from side = damage
Player: On collision with Enemy
// (else branch - not stomping)
→ System: Subtract 1 from PlayerHealth
→ Player: Set Platform vector X to
(Player.X < Enemy.X ? -300 : 300)
// Knockback away from enemy
Polish and Game Feel
The difference between a prototype and a finished platformer is polish. Here are the key effects that make a platformer feel responsive and satisfying.
Coyote time lets the player jump for a short window after walking off a ledge. This is essential for a fair-feeling platformer:
// Coyote time implementation
// Create instance variable "CoyoteTimer" on Player (number, default 0)
// Create instance variable "WasOnFloor" on Player (boolean, default true)
Player: Platform is on floor
→ Player: Set CoyoteTimer to 0.1
→ Player: Set WasOnFloor to true
Player: Platform is NOT on floor
Player: WasOnFloor = true
→ Player: Subtract dt from CoyoteTimer
Player: CoyoteTimer ≤ 0
→ Player: Set WasOnFloor to false
// In your jump input handler, allow jumping when
// CoyoteTimer > 0 even if not on floor
Keyboard: On Space pressed
Player: CoyoteTimer > 0
→ Player: Set Platform vector Y to -650
→ Player: Set CoyoteTimer to 0
Screen shake on impacts adds weight to the game. Use a small random offset on the scroll position for a few frames when the player stomps an enemy or lands from a large height.
Dust particles when the player lands, jumps, or changes direction make movement feel grounded. Create a Particles object and burst a small number of particles at the player’s feet on each of these events.
Variable jump height is expected in modern platformers. When the player releases the jump button early, reduce upward velocity so the jump is shorter:
// Variable jump height
Keyboard: On Space released
Player: Platform is jumping
Player: Platform VectorY < 0
→ Player: Set Platform vector Y to
Player.Platform.VectorY * 0.5
// Cut upward velocity in half for a short hop
Related Issues
If your player falls through the ground after adding the Platform behavior, see Fix: Construct 3 Platform Behavior Falling Through Platforms. For tilemap collision problems, check Fix: Construct 3 Tilemap Collision Not Working. If animations are not switching correctly, see Fix: Construct 3 Animation Not Changing on Trigger. And for performance issues with large levels, see Fix: Construct 3 Performance Low FPS Lag.
Coyote time and variable jump height make the difference between frustrating and fun.