Quick answer: Set persistent = true in the controller’s Create event, remove the controller from the room layout so only the persistent one exists, and guard against duplicates with instance_number.

Your audio controller plays music smoothly in the first room. Walk through a door to the second room and the music cuts out abruptly. The controller was destroyed when the room changed. Setting it persistent works for one transition then duplicates on the next.

How Persistence Works in GameMaker

Every instance has a persistent variable. When false (default), room_goto destroys the instance and triggers its Clean Up event. When true, the instance is preserved and re-inserted into the next room’s instance pool. Its variables, alarm states, and visual properties carry over.

Rooms also have a Persistent flag in Room Properties. A persistent room remembers all of its instances and tile changes across visits.

The bug pattern: developer marks controller persistent, but the controller is also placed in every room’s instance layer. Entering a room creates a fresh controller; the previous persistent one is still there. Now you have two.

The Fix: One Source of Truth

Pick one approach:

A. Persistent controller in only the first room

Remove the controller from every room except the first. In its Create event:

/// obj_controller Create
persistent = true;
// rest of init...
audio_play_sound(snd_music, 100, true);

The instance is created once when the game enters the first room. After that, the controller lives across all room transitions because no other room contains a duplicate.

B. Self-deduplicating singleton

If you can’t guarantee “only first room places it”, add a guard:

/// obj_controller Create
if (instance_number(obj_controller) > 1) {
    instance_destroy();
    exit;
}
persistent = true;
// init...

The second-instantiated copy detects the existing one and destroys itself. The original persists. Defensive but reliable across messy room layouts.

Reset on Game End or Restart

Persistent instances are destroyed by game_restart() and game_end(), so a restart goes through Create again cleanly. If you also have a debug “reset to title” that uses room_goto(rm_title), the persistent controller carries music settings into the title screen — usually unwanted. Explicit cleanup:

/// User Event 0: triggered when returning to title
audio_stop_all();
with (obj_controller) instance_destroy();

Persistent Rooms For Player Progression

For game state — doors the player opened, enemies they defeated — mark the room itself persistent. On re-entry the instances and tile changes survive:

  1. Open the room in the resource tree.
  2. Room Properties → Persistent: checked.
  3. Compile. Re-entering the room restores its state.

Caveat: persistent rooms forget their state when you call room_restart() or game_restart(). For full save support you need an explicit save system.

Verifying

Add a print in Create:

show_debug_message("controller created, count=" + string(instance_number(obj_controller)));

Walk through three rooms. After fix, the message prints once at game start. Without fix, it prints once per room entered.

“Persistent instances need exactly one Create call across the game session. Anything else is a duplicate.”

Singletons in GameMaker are persistent + the instance_number > 1 guard. Build one helper script and reuse.