Header

~Articles This Week~

~12 On Screen Messages~

By StarsInDust

 

In this section we will be looking at how we can display messages, that the user can read on the screen. So far, all that we have had is messages being brought back to us about the game through the output panel. But the player can not see this panel. Being able to speak with the player about certain aspects of the game will be imperative. So, here we will be learning how we can go about doing this.

In order to be able to create these messages we will be implementing a second controller, similar to that other controller which we had built earlier. And instead of just one controller, now we will need to have two that will be thrown into our room.

The Heads Up Display Object

Create an object and name it:

obj_hud

HUD is a shortcut, or Acronym for the words ‘Heads up display’. It is a video game term for providing on-screen messages to the user. We do not need to worry about creating a sprite for this object, as it will be invisible inside of the room.

We will be using two Events for this Heads Up Display object. The first is the create event. Inside of the create event we want to put the very first thing that the display needs to do, and in this case it is to make sure that it is on top of everything else, we do not want any other graphics to be covering this one important element up. The player must be able to see it.

The second event will be the Draw GUI event. This will be used to dynamically draw the number of elements that the player has onto a type of score board that can be seen and utilized by the player to strategically make their way through the game.

Now put this code into the object that you just created.

DO NOT FORGET TO SLIDE INTO ROOM ONCE YOU CREATE THIS OBJECT

 

// ~~~~~~~~~~~~~~~~~HUD OBJECT - Heads-Up Display  ~~~~~~~~~~~~~~~~~~~

// Place it in your room alongside the controller

// This displays hearts, apples, bombs, and floor number on screen

 

 

//  ~~~~~~~~~~~~~~~~~~~~~~~~~ CREATE EVENT ~~~~~~~~~~~~~~~~~~~~~~

depth = -1000;  // Draw on top of everything

 

 

 

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DRAW GUI EVENT~~~~~~~~~~~~~~~~~~~

// Set up text appearance

draw_set_color(c_white);

draw_set_font(-1);  // Default font (or set your own font)

draw_set_halign(fa_left);

draw_set_valign(fa_top);

 

// Draw stats in top-left corner

draw_text(20, 20, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));

draw_text(20, 40, "Apples: " + string(global.apples));

draw_text(20, 60, "Bombs: " + string(global.bombs_held));

draw_text(20, 80, "Floor: " + string(global.current_floor));

 

// Optional: Draw heart icons instead of numbers

// Uncomment this section if you have a heart sprite (spr_heart_icon)

/*

for (var i = 0; i < global.hearts; i++) {

    draw_sprite(spr_heart_icon, 0, 150 + (i * 40), 30);

}

*/

 

// Optional: Draw with background for better readability

/*

// Draw semi-transparent background

draw_set_alpha(0.5);

draw_set_color(c_black);

draw_rectangle(10, 10, 200, 100, false);

draw_set_alpha(1);

 

// Draw text on top

draw_set_color(c_white);

draw_text(20, 20, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));

draw_text(20, 40, "Apples: " + string(global.apples));

draw_text(20, 60, "Bombs: " + string(global.bombs_held));

draw_text(20, 80, "Floor: " + string(global.current_floor));

*/

 

 

 

Do not forget to slide this controller into the room, once it has been created, prior to testing the game. Or you will see nothing.

 

Error Checking

Make sure names of objects are correct, and (as I have said many times) make sure your new controller object is actually inside of the room.

Getting the HUD to work correctly with Restarting the Room

So, far there was not an issue with having the hero reach the door, and what happens. It simply just restarted the floor and we had a new maze. However, you will see that this behavior with the heads up display isn’t quite working. This is because the room is always restarting. Restarting the room, when the hero reaches the door, would acutally be a punishment, they should be allowed to go to the next floor or even successfully leave the dungeon all together.

So, we will need to make a few changes to the code.

Implementation Steps:

STEP 1: Create a new Script in GameMaker

 

// ~~~~~~~~~~~~~~~~~~ REGENERATE MAZE FUNCTION ~~~~~~~~~~~~~~~~~~~~

// Call this function to regenerate the maze without restarting the room

// This preserves all global variables (treasures, floor number, etc.)

// Uses your existing maze generation system

 

function regenerate_maze() {

    show_debug_message("=== REGENERATING MAZE ===");

    show_debug_message("Floor: " + string(global.current_floor));

    show_debug_message("Hearts: " + string(global.hearts) + ", Apples: " + string(global.apples) + ", Bombs: " + string(global.bombs_held));

   

    // STEP 1: Clean up existing maze objects

   

    show_debug_message("Destroying old maze objects...");

   

    // Destroy walls

    with (obj_wall_plain) { instance_destroy(); }

    with (obj_wall_crackedA) { instance_destroy(); }

    with (obj_wall_crackedB) { instance_destroy(); }

   

    // Destroy items

    with (obj_heart) { instance_destroy(); }

    with (obj_apple) { instance_destroy(); }

    with (obj_bomb) { instance_destroy(); }

    with (obj_hazard_bomb) { instance_destroy(); }  // Fixed name!

   

    // Destroy door and thrown bombs

    with (obj_door) { instance_destroy(); }

    with (obj_bomb_thrown) { instance_destroy(); }

   

    show_debug_message("Old objects destroyed.");

   

   

    // STEP 2: Generate new maze using existing system

   

    show_debug_message("Generating new maze...");

   

    var target_width = 1280;

    var target_height = 704;

    var cell_size = 128;

    var maze_width = floor(target_width / cell_size);

    var maze_height = floor(target_height / cell_size);

   

    // New random seed

    var time_seed = get_timer();

    random_set_seed(time_seed);

   

    // Use your existing maze generation system

    global.myMaze = new maze("recursive_backtrack", maze_width, maze_height);

    maze_generate(global.myMaze);

    spawn_maze_walls(global.myMaze, cell_size, 0, 0);

   

   

    // STEP 3: Reposition hero and spawn door

    spawn_object_in_opening(global.myMaze.heroWallSide, global.myMaze.heroPosition, cell_size, global.myMaze.w, global.myMaze.h, object_hero, "Hero");

    spawn_object_in_opening(global.myMaze.doorWallSide, global.myMaze.doorPosition, cell_size, global.myMaze.w, global.myMaze.h, obj_door, "Door");

   

    // Update hero start position

    var hero = instance_find(object_hero, 0);

    if (hero != noone) {

        global.hero_start_x = hero.x;

        global.hero_start_y = hero.y;

    }

   

 

    // STEP 4: Spawn items using existing system

   

    var hearts_to_spawn = irandom_range(1, 2);

    var apples_to_spawn = irandom_range(1, 2);

    var bombs_to_spawn = irandom_range(1, 2);

    var hazards_to_spawn = irandom_range(0, 2);

   

    spawn_guaranteed_items(global.myMaze, cell_size, hearts_to_spawn, apples_to_spawn, bombs_to_spawn, hazards_to_spawn);

   

    show_debug_message("=== MAZE REGENERATION COMPLETE ===");

    show_debug_message("Now on Floor " + string(global.current_floor));

}

 

 

 

STEP 2: Rewrite the Hero’s step event

// Includes item collection, damage handling, and bomb throwing

 

// MOVEMENT INPUT (Your existing code)

var move_x = keyboard_check(vk_right) - keyboard_check(vk_left);

var move_y = keyboard_check(vk_down)  - keyboard_check(vk_up);

 

var spd = 4;

var dx  = move_x * spd;

var dy  = move_y * spd;

 

// COLLISION CHECK & MOVEMENT with WALL GLIDING

if (dx != 0 || dy != 0) {

    // Check full diagonal move

    if (!place_meeting(x + dx, y + dy, obj_wall_plain) &&

        !place_meeting(x + dx, y + dy, obj_wall_crackedA) &&

        !place_meeting(x + dx, y + dy, obj_wall_crackedB)) {

        x += dx;

        y += dy;

    } else {

        // Wall gliding: Try to slide along walls smoothly

        var moved = false;

       

        // Try horizontal only

        if (dx != 0 && !place_meeting(x + dx, y, obj_wall_plain) &&

            !place_meeting(x + dx, y, obj_wall_crackedA) &&

            !place_meeting(x + dx, y, obj_wall_crackedB)) {

            x += dx;

            moved = true;

        }

 

        // Try vertical only

        if (dy != 0 && !place_meeting(x, y + dy, obj_wall_plain) &&

            !place_meeting(x, y + dy, obj_wall_crackedA) &&

            !place_meeting(x, y + dy, obj_wall_crackedB)) {

            y += dy;

            moved = true;

        }

       

        // If still stuck in wall - AGGRESSIVE AUTO-ESCAPE

        if (place_meeting(x, y, obj_wall_plain) ||

            place_meeting(x, y, obj_wall_crackedA) ||

            place_meeting(x, y, obj_wall_crackedB)) {

           

            show_debug_message("HERO STUCK IN WALL - AUTO ESCAPING!");

           

            // Try to nudge out in 8 directions with larger distance

            var nudge_distance = 16; 

            var escaped = false;

           

            for (var angle = 0; angle < 360; angle += 45) {

                var nudge_x = lengthdir_x(nudge_distance, angle);

                var nudge_y = lengthdir_y(nudge_distance, angle);

               

                if (!place_meeting(x + nudge_x, y + nudge_y, obj_wall_plain) &&

                    !place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedA) &&

                    !place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedB)) {

                    x += nudge_x;

                    y += nudge_y;

                    escaped = true;

                    show_debug_message("Hero auto-escaped from wall at angle " + string(angle) + "!");

                    break;

                }

            }

           

            // If 16px didn't work, try 32px

            if (!escaped) {

                show_debug_message("Trying larger escape distance...");

                nudge_distance = 32;

               

                for (var angle = 0; angle < 360; angle += 45) {

                    var nudge_x = lengthdir_x(nudge_distance, angle);

                    var nudge_y = lengthdir_y(nudge_distance, angle);

                   

                    if (!place_meeting(x + nudge_x, y + nudge_y, obj_wall_plain) &&

                        !place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedA) &&

                        !place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedB)) {

                        x += nudge_x;

                        y += nudge_y;

                        escaped = true;

                        show_debug_message("Hero escaped at 32px distance!");

                        break;

                    }

                }

            }

           

            // Last resort - teleport to calculated safe position

            if (!escaped) {

                show_debug_message("Could not auto-escape - finding safe location!");

               

                // Calculate center of room as fallback

                var safe_x = room_width / 2;

                var safe_y = room_height / 2;

               

                // If center is also in wall, try a grid search for ANY safe spot

                if (place_meeting(safe_x, safe_y, obj_wall_plain) ||

                    place_meeting(safe_x, safe_y, obj_wall_crackedA) ||

                    place_meeting(safe_x, safe_y, obj_wall_crackedB)) {

                   

                    show_debug_message("Center blocked - searching for safe spot...");

                    var found_safe = false;

                   

                    // Search in a grid pattern for a safe spot

                    for (var check_x = 128; check_x < room_width - 128; check_x += 64) {

                        for (var check_y = 128; check_y < room_height - 128; check_y += 64) {

                            if (!place_meeting(check_x, check_y, obj_wall_plain) &&

                                !place_meeting(check_x, check_y, obj_wall_crackedA) &&

                                !place_meeting(check_x, check_y, obj_wall_crackedB)) {

                                safe_x = check_x;

                                safe_y = check_y;

                                found_safe = true;

                                break;

                            }

                        }

                        if (found_safe) break;

                    }

                }

               

                x = safe_x;

                y = safe_y;

                show_debug_message("Teleported to safe location: (" + string(safe_x) + ", " + string(safe_y) + ")");

            }

        }

    }

}

 

// EMERGENCY ESCAPE SYSTEM

// Press R to find a safe position (doesn't rely on spawn being safe)

if (keyboard_check_pressed(ord("R"))) {

    show_debug_message("=== EMERGENCY ESCAPE ACTIVATED ===");

   

    // First try the original spawn position

    if (!place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_plain) &&

        !place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_crackedA) &&

        !place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_crackedB)) {

        x = global.hero_start_x;

        y = global.hero_start_y;

        show_debug_message("Returned to spawn: (" + string(x) + ", " + string(y) + ")");

    } else {

        // Spawn is blocked, find a safe spot

        show_debug_message("Spawn blocked - searching for safe location...");

       

        var safe_x = room_width / 2;

        var safe_y = room_height / 2;

       

        // If center is also in wall, do a grid search

        if (place_meeting(safe_x, safe_y, obj_wall_plain) ||

            place_meeting(safe_x, safe_y, obj_wall_crackedA) ||

            place_meeting(safe_x, safe_y, obj_wall_crackedB)) {

           

            var found_safe = false;

           

            // Search in a grid pattern for ANY safe spot

            for (var check_x = 128; check_x < room_width - 128; check_x += 64) {

                for (var check_y = 128; check_y < room_height - 128; check_y += 64) {

                    if (!place_meeting(check_x, check_y, obj_wall_plain) &&

                        !place_meeting(check_x, check_y, obj_wall_crackedA) &&

                        !place_meeting(check_x, check_y, obj_wall_crackedB)) {

                        safe_x = check_x;

                        safe_y = check_y;

                        found_safe = true;

                        break;

                    }

                }

                if (found_safe) break;

            }

        }

       

        x = safe_x;

        y = safe_y;

        show_debug_message("Escaped to safe location: (" + string(safe_x) + ", " + string(safe_y) + ")");

    }

   

    // Optional: Play a sound effect

    // audio_play_sound(snd_teleport, 1, false);

}

 

// DEBUG: FORCE HERO INTO WALL (TEMPORARY - REMOVE AFTER TESTING)

// Press T to teleport hero into a wall for testing the escape system

if (keyboard_check_pressed(ord("T"))) {

    // Find a wall and teleport hero into it

    var test_wall = instance_find(obj_wall_plain, 0);

   

    if (test_wall != noone) {

        x = test_wall.x;

        y = test_wall.y;

        show_debug_message("=== DEBUG: TELEPORTED INTO WALL FOR TESTING ===");

        show_debug_message("Position: (" + string(x) + ", " + string(y) + ")");

        show_debug_message("Press R to test emergency escape!");

    } else {

        show_debug_message("No walls found to teleport into.");

    }

}

 

// SPRITE SWITCHING (Your existing code)

if (move_y < 0) {

    sprite_index = sprite_hero_back;

} else if (move_x > 0) {

    sprite_index = sprite_hero_right;

} else if (move_x < 0) {

    sprite_index = sprite_hero_left;

} else {

    sprite_index = sprite_hero;

}

 

 

// NEW: ITEM COLLECTION

// --- Collect Heart ---

var item_heart = instance_place(x, y, obj_heart);

if (item_heart != noone) {

    // Heal 1 heart

    global.hearts += 1;

    if (global.hearts > global.max_hearts) {

        global.hearts = global.max_hearts;

    }

   

    show_debug_message("Collected heart! Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));

    instance_destroy(item_heart);

   

    // Optional: Play sound effect

    // audio_play_sound(snd_collect_heart, 1, false);

}

 

// --- Collect Apple (Gysahi Greens style) ---

var item_apple = instance_place(x, y, obj_apple);

if (item_apple != noone) {

    global.apples += 1;

   

    show_debug_message("Collected apple! Total: " + string(global.apples));

    instance_destroy(item_apple);

   

    // Optional: Add special effect (like in Chocobo's Dungeon)

    // Could heal 1 heart or give temporary speed boost

    // audio_play_sound(snd_collect_apple, 1, false);

}

 

// --- Collect Bomb (Gold pickup) ---

var item_bomb = instance_place(x, y, obj_bomb);

if (item_bomb != noone) {

    global.bombs_held += 1;

   

    show_debug_message("Picked up bomb! Total bombs: " + string(global.bombs_held));

    instance_destroy(item_bomb);

   

    // Optional: Play sound effect

    // audio_play_sound(snd_collect_bomb, 1, false);

}

 

 

// NEW: BOMB THROWING

// Press SPACE to throw a bomb

 

if (keyboard_check_pressed(vk_space)) {

    if (global.bombs_held > 0) {

        global.bombs_held -= 1;

       

        // Determine throw direction based on sprite

        var throw_direction = 270;  // Default: down

       

        if (sprite_index == sprite_hero_back) {

            throw_direction = 90;   // Throw up

        } else if (sprite_index == sprite_hero_right) {

            throw_direction = 0;    // Throw right

        } else if (sprite_index == sprite_hero_left) {

            throw_direction = 180;  // Throw left

        } else {

            throw_direction = 270;  // Throw down

        }

       

        // Create the bomb projectile slightly ahead of hero

        var offset_distance = 32;  // Spawn bomb 32 pixels ahead

        var bomb_x = x + lengthdir_x(offset_distance, throw_direction);

        var bomb_y = y + lengthdir_y(offset_distance, throw_direction);

       

        var bomb = instance_create_layer(bomb_x, bomb_y, "Instances", obj_bomb_thrown);

        bomb.direction = throw_direction;

        bomb.image_angle = throw_direction;

       

        show_debug_message("Threw bomb! Bombs remaining: " + string(global.bombs_held));

       

        // Optional: Play throw sound

        // audio_play_sound(snd_throw_bomb, 1, false);

    } else {

        show_debug_message("No bombs to throw!");

    }

}

 

 

// NEW: CHECK FOR HAZARDS (Black hazard bomb damages you)

// obj_hazard_bomb is the BLACK hazard bomb that damages the hero

 

var hazard_bomb = instance_place(x, y, obj_hazard_bomb);

if (hazard_bomb != noone) {

    // Take damage

    global.hearts -= 1;

   

    show_debug_message("Hit a black bomb! Lost 1 heart. Hearts remaining: " + string(global.hearts));

   

    // Destroy the hazard

    instance_destroy(hazard_bomb);

   

    // Check if hero died

    if (global.hearts <= 0) {

        show_debug_message("Hero died! Resetting to floor start...");

       

        // Teleport back to start

        x = global.hero_start_x;

        y = global.hero_start_y;

       

        // Reset hearts

        global.hearts = 3;

       

        show_debug_message("Respawned at: (" + string(x) + ", " + string(y) + ")");

        show_debug_message("Hearts restored to: " + string(global.hearts));

    }

   

    // Optional: Play damage sound and show damage animation

    // audio_play_sound(snd_take_damage, 1, false);

}

 

 

// CHECK FOR EXIT (Your existing code)

if (place_meeting(x, y, obj_door)) {

    show_debug_message("Hero reached the dungeon exit!");

    global.current_floor += 1;

    show_debug_message("Advancing to floor " + string(global.current_floor));

    regenerate_maze();  // NEW - keeps treasures and floor number

}

Seeing the Heads Up Display Better

Right now,(if you were to run the game) you will see that the Heads up Display, is done in white text, and it is also off to the left side of the dungeon, just a bit. We might want to change this positioning and give the text a background and maybe even a border. This way we can see it better inside of any dungeon with any color background.

Above, you can see what the code is giving us so far. With just a few more changes to our code, we can change it to look like a scoreboard type of heads-up-display that we have in the image below.

 

// ~~~~~~~~~~~~~~~~~   HUD OBJECT - Heads-Up Display ~~~~~~~~~~~~~~~~~~~

 

// DRAW GUI EVENT

// Set up HUD panel dimensions

var hud_width = 200;

var hud_height = 110;

var padding = 10;

 

// Center the HUD at the top of the screen

var gui_width = display_get_gui_width();

var hud_x = (gui_width / 2) - (hud_width / 2);

var hud_y = 10;

 

// Draw background panel (semi-transparent black)

draw_set_alpha(0.7);

draw_set_color(c_black);

draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, false);

 

// Draw border (white outline)

draw_set_alpha(1);

draw_set_color(c_white);

draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, true);

 

// Draw inner border for extra visibility

draw_set_color(c_dkgray);

draw_rectangle(hud_x + 1, hud_y + 1, hud_x + hud_width - 1, hud_y + hud_height - 1, true);

 

// Set up text appearance

draw_set_color(c_white);

draw_set_font(-1);  // Default font (or set your own font)

draw_set_halign(fa_left);

draw_set_valign(fa_top);

draw_set_alpha(1);

 

// Draw stats inside the panel

var text_x = hud_x + padding;

var text_y = hud_y + padding;

var line_height = 20;

 

draw_text(text_x, text_y, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));

draw_text(text_x, text_y + line_height, "Apples: " + string(global.apples));

draw_text(text_x, text_y + line_height * 2, "Bombs: " + string(global.bombs_held));

draw_text(text_x, text_y + line_height * 3, "Floor: " + string(global.current_floor));

 

// Optional: Draw heart icons instead of numbers

// Uncomment this section if you have a heart sprite (spr_heart_icon)

/*

for (var i = 0; i < global.hearts; i++) {

    draw_sprite(spr_heart_icon, 0, text_x + 80 + (i * 20), text_y + 5);

}

*/

 

 

Drawing a Heart instead of using Numbers

When we finish with this next section, this is what your scoreboard should be looking like. Sporting some cute little hearts in place of using a count displayed in numbers. This will certainly give this little section of your game board a bit more pizasz.

 

In order to accomplish this, first we will need to make another sprite. We can use the heart sprite that we already have for a pickup, but save in in a 16 x16 size, inside of Photoshop and throw it back into the Game Maker Game folder, so we can make a sprite out of it.

C:\Users\YOUR_USER_NAME\GameMakerProjects

 

Since this sprite will be used in code, you will need to name it exactly like this:

 

spr_heart_icon

Notice that the code will call directly to the sprite, there is no need to use an object. The Draw code can draw the sprite, just as a sprite.

Remember, though to import the little sprite image for your new icon.

 

Now, if you do want to go this route, and make little hearts as opposed to using a count, we will need to replace the code in both the HUD Object, and the Object Controllers, Create Event.

 

 

 

Rewrite the Draw GUI Event for the HUD Object

 // ~~~~~~~~~~~~~~~ HUD Object -DRAW GUI EVENT ~~~~~~~~~~~~~~~~~~~~~~

 

// Set up HUD panel dimensions

var hud_width = 200;

var hud_height = 110;

var padding = 10;

 

// Center the HUD at the top of the screen

var gui_width = display_get_gui_width();

var hud_x = (gui_width / 2) - (hud_width / 2);

var hud_y = 10;

 

// Draw background panel (semi-transparent black)

draw_set_alpha(0.7);

draw_set_color(c_black);

draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, false);

 

// Draw border (white outline)

draw_set_alpha(1);

draw_set_color(c_white);

draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, true);

 

// Draw inner border for extra visibility

draw_set_color(c_dkgray);

draw_rectangle(hud_x + 1, hud_y + 1, hud_x + hud_width - 1, hud_y + hud_height - 1, true);

 

// Set up text appearance

draw_set_color(c_white);

draw_set_font(-1);  // Default font (or set your own font)

draw_set_halign(fa_left);

draw_set_valign(fa_top);

draw_set_alpha(1);

 

// Draw stats inside the panel

var text_x = hud_x + padding;

var text_y = hud_y + padding;

var line_height = 20;

 

// Draw "Hearts:" label

draw_text(text_x, text_y, "Hearts:");

 

// Draw heart icons - filled hearts for current health, empty for lost health

var heart_start_x = text_x + 70;  // Position after "Hearts:" text with padding

var heart_spacing = 18;  // Space between each heart icon

 

// Draw filled hearts for current health

for (var i = 0; i < global.hearts; i++) {

    draw_sprite(spr_heart_icon, 0, heart_start_x + (i * heart_spacing), text_y + 2);

}

 

// Draw empty/grayed hearts for lost health

for (var i = global.hearts; i < global.max_hearts; i++) {

    draw_sprite_ext(spr_heart_icon, 0, heart_start_x + (i * heart_spacing), text_y + 2,

                    1, 1, 0, c_gray, 0.4);  // Gray and semi-transparent for lost hearts

}

 

// Draw other stats

draw_text(text_x, text_y + line_height, "Apples: " + string(global.apples));

draw_text(text_x, text_y + line_height * 2, "Bombs: " + string(global.bombs_held));

draw_text(text_x, text_y + line_height * 3, "Floor: " + string(global.current_floor));

 

 

 

In the obj_controller – Create Event

//~~~~~~~~~~  CONTROLLER OBJECT CREATE EVENT ~~~~~~~~~~~~~~~~~~~~~~

// Integrates item system with maze generation

// for 1280x704 room size

 

 

// STEP 1: INITIALIZE ITEM SYSTEM

 

show_debug_message("=== INITIALIZING ITEM SYSTEM ===");

 

global.hearts = 3;              // Starting lives

global.max_hearts = 5;          // Maximum hearts

global.apples = 0;              // Gysahi Greens counter

global.bombs_held = 0;          // Bombs in inventory

global.current_floor = 1;       // Current dungeon floor

global.hero_start_x = 0;        // Will be saved after spawn

global.hero_start_y = 0;        // Will be saved after spawn

 

show_debug_message("Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));

show_debug_message("Floor: " + string(global.current_floor));

show_debug_message("=== ITEM SYSTEM READY ===");

 

 

 

// STEP 2: GENERATE MAZE (Your existing code)

 

var target_width = 1280;

var target_height = 704;

var cell_size = 128;

 

var maze_width = floor(target_width / cell_size);

var maze_height = floor(target_height / cell_size);

 

show_debug_message("=== CREATING MAZE FOR NEW ROOM SIZE ===");

show_debug_message("Room dimensions: " + string(target_width) + " x " + string(target_height));

show_debug_message("Creating maze: " + string(maze_width) + " x " + string(maze_height) + " cells");

show_debug_message("Cell size: " + string(cell_size) + "px");

show_debug_message("Wall size: 32px");

 

var time_seed = get_timer();

random_set_seed(time_seed);

show_debug_message("Random seed set to: " + string(time_seed));

show_debug_message("Testing random values: " + string(irandom(100)) + ", " + string(irandom(100)) + ", " + string(irandom(100)));

 

// Create and generate the maze

global.myMaze = new maze("recursive_backtrack", maze_width, maze_height);

maze_generate(global.myMaze);

 

// Spawn the maze walls

spawn_maze_walls(global.myMaze, cell_size, 0, 0);

 

// Spawn hero and door

spawn_object_in_opening(global.myMaze.heroWallSide, global.myMaze.heroPosition, cell_size, global.myMaze.w, global.myMaze.h, object_hero, "Hero");

spawn_object_in_opening(global.myMaze.doorWallSide, global.myMaze.doorPosition, cell_size, global.myMaze.w, global.myMaze.h, obj_door, "Door");

 

show_debug_message("=== MAZE SETUP COMPLETE ===");

 

 

 

// STEP 3: SAVE HERO STARTING POSITION

 

show_debug_message("=== SAVING HERO START POSITION ===");

 

var hero = instance_find(object_hero, 0);

if (hero != noone) {

    global.hero_start_x = hero.x;

    global.hero_start_y = hero.y;

   

    show_debug_message("Hero start position saved: (" + string(global.hero_start_x) + ", " + string(global.hero_start_y) + ")");

} else {

    show_debug_message("WARNING: Could not find hero to save position!");

}

 

// STEP 4: SPAWN ITEMS IN MAZE

 

// Balanced spawning: 1-2 of each item type

 

// Random amount between 1-2 for each item

var hearts_to_spawn = irandom_range(1, 2);

var apples_to_spawn = irandom_range(1, 2);

var bombs_to_spawn = irandom_range(1, 2);

var hazards_to_spawn = irandom_range(1, 2);  // 1-2 hazard bombs (guaranteed spawn)

 

spawn_guaranteed_items(global.myMaze, cell_size, hearts_to_spawn, apples_to_spawn, bombs_to_spawn, hazards_to_spawn);

 

// Alternative methods (comment out the above and uncomment one of these):

// OPTION 1: Pure random spawning (adjust spawn_chance in function)

// spawn_items_in_maze(global.myMaze, cell_size);

 

// OPTION 2: Fixed exact counts (hearts, apples, good bombs, hazard bombs)

// spawn_guaranteed_items(global.myMaze, cell_size, 2, 2, 2, 1);

 

show_debug_message("=== DUNGEON FLOOR " + string(global.current_floor) + " READY ===");