Quick answer: Your Step event is overwriting sprite_index every frame, resetting it before the animation can play. Use a state variable to track the current animation and only assign sprite_index when the state changes. Handle one-shot animations in the Animation End event.
Here is how to fix sprite_index resetting after animation end in GameMaker. You set sprite_index = spr_attack when the player presses the attack button. The attack animation flashes for a single frame and then snaps back to the idle sprite. Or the attack animation plays fully but then loops instead of returning to idle. You expected a clean one-shot animation followed by a return to the default state, but the animation system fights you at every step.
The Symptom
You change sprite_index to play an animation (attack, jump, hurt, death). One of these happens: the animation plays for one frame and resets, the animation loops endlessly instead of playing once, or the animation completes but the sprite freezes on the last frame instead of returning to idle. Sometimes all three happen in different parts of the same game because each animation is handled inconsistently.
What Causes This
1. Step event overwrites sprite_index every frame. The most common mistake is code like this in the Step event:
// Step Event - THE BUG
if (moving)
{
sprite_index = spr_player_run;
}
else
{
sprite_index = spr_player_idle; // This runs every frame you're not moving
}
// This sets the attack sprite, but next step the code above overwrites it
if (keyboard_check_pressed(vk_space))
{
sprite_index = spr_player_attack;
}
The attack sprite is set for one frame. The next frame, the if/else block runs first and sets it back to idle or run.
2. No Animation End handler. GameMaker does not automatically stop or transition animations. When an animation reaches its last frame, image_index wraps to 0 and the animation loops. Without an Animation End event to handle the transition, one-shot animations loop forever.
3. image_index not reset on sprite change. When you change sprite_index, image_index does not automatically reset to 0. If the previous sprite was on frame 5 and the new sprite has 4 frames, the animation starts on the wrong frame or wraps immediately.
The Fix
Step 1: Use a state machine for animations.
// Create Event
state = "idle";
// Step Event
switch (state)
{
case "idle":
sprite_index = spr_player_idle;
if (moving) state = "run";
if (keyboard_check_pressed(vk_space))
{
state = "attack";
sprite_index = spr_player_attack;
image_index = 0; // Start from frame 0
}
break;
case "run":
sprite_index = spr_player_run;
if (!moving) state = "idle";
if (keyboard_check_pressed(vk_space))
{
state = "attack";
sprite_index = spr_player_attack;
image_index = 0;
}
break;
case "attack":
// Do NOT change sprite_index here
// Let the animation play through
// Transition handled in Animation End event
break;
}
Step 2: Handle Animation End for one-shot transitions.
// Animation End Event
if (state == "attack")
{
// Attack animation finished, return to appropriate state
if (moving)
{
state = "run";
}
else
{
state = "idle";
}
}
if (state == "hurt")
{
state = "idle";
}
Step 3: Freeze on last frame when needed. For death animations or charge-up effects that should hold on the final frame:
// Animation End Event
if (state == "death")
{
image_speed = 0; // Freeze on last frame
image_index = image_number - 1; // Ensure it's the last frame
}
“GameMaker animations loop by default. Every animation. Always. If you want an animation to play once and stop or transition, you must explicitly handle it in the Animation End event. There is no ‘play once’ setting.”
Why This Works
GameMaker’s animation system is deliberately simple: each step, image_index advances by image_speed. When image_index exceeds image_number - 1, it wraps to 0 and the Animation End event fires. There is no built-in concept of one-shot animations, animation queues, or state transitions. The state machine pattern gives you explicit control over when sprite_index changes, preventing the Step event from overwriting animations that should play through. The Animation End event provides the hook for transitioning back to looping animations after a one-shot completes.
Related Issues
If your sprite changes but the collision mask does not update, check that each sprite has the correct collision mask shape. Changing sprite_index changes the collision mask to match the new sprite, which can cause unexpected physics behavior during animation transitions.
For alarm-based animation timing (playing an animation for a fixed duration regardless of frame count), see Fix: GameMaker Alarm Not Firing for reliable timer patterns.
State machine in Step, transitions in Animation End. Never set sprite_index unconditionally.