Quick answer: Room Creation Code runs after every instance's Create event, does not run on room_restart, and does not run when re-entering a room that contains persistent objects. If you need setup logic to run every time, move it into a controller object's Room Start event instead.
You added some important setup logic to your room's Creation Code — spawn positions, difficulty scaling, background music, whatever — and it worked once. Then you started testing, and now it only runs occasionally. Sometimes it runs. Sometimes it does not. Sometimes it runs but after the Create events of the instances it was supposed to configure. Room Creation Code is one of the most misunderstood features in GameMaker, and almost every studio has a "don't touch it" rule by year two. Here is how to make it reliable.
The Symptom
You drop code into the Creation Code field of a room (right-click the room in the IDE → Creation Code). The code might set a global, play a cutscene, position the camera, or initialize enemies. You test it and it works. Later you find that:
- Calling
room_restartdoes not re-run the Creation Code - Returning to the room from a menu skips the Creation Code
- Variables set in Creation Code are
undefinedwhen Create events of objects in the room try to read them - The code runs but its effects are immediately overwritten by an object's Create event
What Causes This
1. Execution order surprises most developers. The actual order of events when you enter a room is:
- All instances are created and their Create events run (in creation order)
- Each instance's Instance Creation Code runs (per-instance code set in the room editor)
- The Room Creation Code runs (once, for the whole room)
- Each instance's Room Start event runs
If your Create event reads a global that Room Creation Code is supposed to set, the global is undefined because step 1 runs before step 3.
2. room_restart() does not re-run Creation Code. The GameMaker documentation has confirmed this behavior across versions. room_restart destroys non-persistent instances, recreates them, and fires their events — but the Room Creation Code is skipped. Only room_goto(room_current) will re-trigger it (and even that has caveats).
3. Persistent objects short-circuit the flow. If the room contains a persistent object from a previous visit, GameMaker treats the room as "already set up" and skips some of the initialization events, including Room Creation Code, when you re-enter.
4. Save/load interactions. Loading a saved game puts the player back in a room without triggering Creation Code, because the engine assumes the save contains everything it needs.
The Fix
Step 1: Move room setup into a controller object.
Create an object called obj_room_controller, drop it in every room, and put your setup logic in a Room Start event. This event runs every time the room starts, including after room_restart and when re-entering the room.
// obj_room_controller: Create event
// Runs once when the instance is first created
difficulty_multiplier = 1.0;
wave_number = 0;
// obj_room_controller: Room Start event
// Runs every time the room starts
switch (room) {
case rm_level_1:
difficulty_multiplier = 1.0;
wave_number = 1;
audio_play_sound(snd_music_level_1, 10, true);
break;
case rm_level_2:
difficulty_multiplier = 1.5;
wave_number = 1;
audio_play_sound(snd_music_level_2, 10, true);
break;
}
// Position the player at the spawn marker
var spawn = instance_find(obj_spawn_marker, 0);
if (instance_exists(spawn)) {
with (obj_player) {
x = spawn.x;
y = spawn.y;
}
}
Step 2: Use a persistent GameController, not persistent level objects.
Persistence is useful for truly global state (the player's inventory, game time, score) but destructive for level state. Keep one persistent obj_game_controller that lives across all rooms, and make all level-specific objects non-persistent. This gives you predictable Room Start behavior every time.
// obj_game_controller: Create event
// Mark Persistent in the object properties
global.player_hp = 100;
global.player_score = 0;
global.coins = 0;
Step 3: If you must use Room Creation Code, set flags not state.
A narrow use case for Room Creation Code is flipping simple flags that the controller object's Room Start event will then read. Because Room Creation Code runs before Room Start, this ordering is safe.
// Room Creation Code (rm_boss_arena)
global.boss_variant = "hard";
global.spawn_minions = true;
// obj_room_controller: Room Start event
if (global.boss_variant == "hard") {
boss_hp_multiplier = 2.0;
}
if (global.spawn_minions) {
instance_create_layer(500, 300, "Enemies", obj_minion);
}
This pattern is fragile but version-control friendly: the Room Creation Code lives in the .yy file so changes are trackable, and the controller object code is where the debugging happens.
Why This Works
The Room Start event fires reliably on every room entry regardless of how you got there — room_goto, room_restart, loading a save, or returning from a sub-room. It runs after Creation events, so any globals set in Room Creation Code are available to read. And because your setup logic lives in code that the debugger can step through, you can set a breakpoint on it and see exactly what runs when.
"The only GameMaker code I fully trust is code that lives in an object event. Everything else is a scripting language for the room editor."
Related Issues
For more GameMaker export-specific bugs see GameMaker audio not playing on Android export. For managing global state across rooms safely, the persistent controller pattern pairs well with save migration strategies from save file migration debugging.
Room Creation Code is a trap. Use a persistent controller object with a Room Start event. Trust me.