Quick answer: Events run Step → Draw. Cache previous position in End Step for smooth interpolation; never put rendering inside Step events.
Player movement looks jittery despite high frame rate. Each draw shows the position right after the step ran, but the visual feels off — sometimes ahead, sometimes behind. The issue is mixing per-step state with per-frame rendering without smoothing.
Event Lifecycle in One Tick
GameMaker’s per-tick order:
- Begin Step (rarely used)
- Step (movement, AI, logic)
- End Step (post-logic adjustments, e.g., camera follow)
- Collision (resolved as Step runs)
- Draw Begin
- Draw (sprites, UI)
- Draw End
Position updates happen in Step. Draw reads the result. If you want interpolation between ticks for smooth visuals at higher render rates, you need to remember the previous position.
Cache Previous Position
/// Create
xprev = x;
yprev = y;
/// End Step
xprev = x;
yprev = y;
/// Step (movement)
x += hspeed;
y += vspeed;
/// Draw
var alpha = delta_time / room_speed_us; // fractional tick
var draw_x = lerp(xprev, x, alpha);
var draw_y = lerp(yprev, y, alpha);
draw_sprite(sprite_index, image_index, draw_x, draw_y);
Wait — in End Step we save the new x, but Step happens before End Step. Adjust: save in Begin Step (before motion) or use a dedicated “previous frame after physics” pattern. The simplest correct version:
/// Begin Step — before Step movement
xprev = x;
yprev = y;
Begin Step saves the pre-step position. Step then moves to the new x. Draw lerps from old to new for smooth interpolation.
Don’t Draw in Step
Calling draw_sprite from a Step event “works” but breaks GameMaker’s draw cycle. The render passes wouldn’t set up matrices and depth correctly. Always use Draw events.
Camera Update in End Step
For a follow camera that should be perfectly aligned with the player’s new position:
/// obj_camera End Step
camera_set_view_pos(view_camera[0], target.x - vw/2, target.y - vh/2);
End Step runs after the target’s Step, so the camera sees its final position. Putting this in regular Step risks reading pre-move target position.
Verifying
Walk at a slow speed. With proper interpolation in Draw, motion looks buttery smooth. Without, you see step-sized jumps at the room_speed tick rate.
“Step writes, Draw reads. Save previous in Begin Step to enable smooth interpolation in Draw.”
Add xprev/yprev to your “base entity” parent object — every moving entity inherits the smoothing for free.