Quick answer: The black frame occurs because the old room is destroyed before the new room draws its first frame. Use a persistent transition controller object that draws a full-screen overlay (solid color or captured surface) across the room change. The persistent object survives room destruction and covers the gap.

Here is how to fix GameMaker room transition flicker black frame. You call room_goto(rm_level2) and for a single frame, the screen flashes black before the new room appears. It happens every time — a jarring one-frame flicker that breaks the feel of your game. The black frame is not a bug in GameMaker; it is the natural consequence of room destruction and creation happening on adjacent frames with nothing drawn in between.

The Symptom

When transitioning between rooms using room_goto, room_goto_next, or any room change function, there is exactly one frame where the screen goes completely black (or shows the room background color). This is visible as a quick flicker, especially noticeable on monitors with slow pixel response times or when recording gameplay.

What Causes This

Room destruction before new room draws. When room_goto is called, GameMaker queues the room change for end of step. At end of step, all non-persistent instances are destroyed, surfaces are freed, and the room data is unloaded. The new room’s Create events run, but the Draw event has not happened yet. The next frame draws the new room, but there is one frame of nothing in between.

No persistent draw layer. Without a persistent object that draws every frame (including during the transition), nothing covers the gap between old room destruction and new room first draw.

Surfaces freed on room change. If you captured the last frame to a surface, that surface is freed when the room changes (surfaces are volatile in GameMaker). You cannot draw the old frame in the new room unless you used a persistent object and buffer-backed surface.

Draw event order in new room. Even with persistent objects, if your persistent object’s Draw event has lower depth than the new room’s objects, it draws behind them on the first frame, not covering the gap.

The Fix

Step 1: Create a persistent transition controller.

/// obj_transition - Create Event
persistent = true;
fade_alpha = 0;
fade_speed = 0.05;
state = "idle";  // idle, fading_out, fading_in
target_room = -1;
depth = -9999;  // Draw on top of everything

The object is persistent (survives room changes) and draws at the lowest depth (highest visual priority).

Step 2: Implement fade out, transition, fade in.

/// obj_transition - Step Event
switch (state) {
    case "fading_out":
        fade_alpha += fade_speed;
        if (fade_alpha >= 1.0) {
            fade_alpha = 1.0;
            room_goto(target_room);
            state = "fading_in";
        }
        break;

    case "fading_in":
        fade_alpha -= fade_speed;
        if (fade_alpha <= 0) {
            fade_alpha = 0;
            state = "idle";
        }
        break;
}

The room change happens when the screen is fully black (fade_alpha = 1.0). The black frame is invisible because the overlay is already solid black.

Step 3: Draw the overlay.

/// obj_transition - Draw GUI Event
if (fade_alpha > 0) {
    draw_set_alpha(fade_alpha);
    draw_set_colour(c_black);
    draw_rectangle(0, 0, display_get_gui_width(), display_get_gui_height(), false);
    draw_set_alpha(1);
}

Using Draw GUI ensures the overlay draws on top of everything regardless of camera position or view. The overlay covers the entire screen during the transition frame.

Step 4: Trigger transitions from gameplay code.

/// When player reaches exit:
with (obj_transition) {
    target_room = rm_level2;
    state = "fading_out";
}

// Or create a script function:
function transition_to(_room) {
    with (obj_transition) {
        target_room = _room;
        state = "fading_out";
    }
}

Never call room_goto directly from gameplay. Always route through the transition controller so the fade covers the black frame.

“Room transitions always have a gap frame. The fix is not preventing the gap — it is covering it. A persistent overlay drawn at top depth hides the seam.”

Related Issues

For persistent object patterns across rooms, ensure your transition controller is placed in the first room of the game or created programmatically on game start. For surface management across rooms, always back surfaces with buffers since surfaces are volatile.

Persistent controller, fade to black before room_goto, fade in after. The gap frame is hidden.