• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM [SOLVED] Creating a minimap

S

Shawn

Guest
Done all that I can to get this working, and it's been nothing but dead-ends.
 
S

Shawn

Guest
So, I found this:
Code:
//Create

/// Init
oSurface = -1;


//Step

//Your Values can be optional. This is what i am currently using.
if (!surface_exists(oSurface))
{
   oSurface = surface_create(400, 400);
}
surface_set_target(oSurface);
draw_clear(c_white);

//This part is optional
draw_set_alpha(0.7);
draw_background_tiled(bg, 0, 0);
draw_set_alpha(1);

//Get objects for population on map
var numObjects = instance_number(par_minimap)

for ( var i = 0; i < numObjects; i++ )
{
   var obj = instance_find( par_minimap, i );
   var _px = obj_player.x
   var _py = obj_player.y
   with(obj)
   {
       draw_sprite( sprite_index, 1, x+200 - _px, y+200 - _py);
   }
}
surface_reset_target();



//Draw GUI

if (surface_exists(oSurface))
{
   //Your Values can be optional. This is what i am currently using.
   draw_surface_stretched( oSurface, 0, 60, 200, 200 );

   var old = draw_get_color();

   // Get underlay color.
   draw_set_color(c_white);

   //Your Values can be optional. This is what i am currently using.
   draw_rectangle( 0, 60, 200+0, 200+60, true);

   draw_set_color(old);
}
and I was wondering if there was a way to make it look at tiles. I used objects on the walls so they're solid and allow for particles, but I stretch the objects to cover the entirety of the area of the wall I make solid, to reduce the required resources, but this makes them only appear as a single square, and the wall objects are a solid color, since they're just invisible because I use tiles for the graphics of the walls. I'm still looking through the code, and it is working, even though it brings the framerate down to around 600fps after I changed the scaling on it to scale with the resolution and aspect ratio, but this has been the closest thing to a proper minimap I've found, so far, and 600fps is still acceptable.


Mostly, I'm not sure how to check for a tile like you can check for an object. I found that there's a tile_find function, but can't find information on it in the manual and the game doesn't give the little tips on it like it does with other functions.
 
Last edited by a moderator:
S

Shawn

Guest
So, I found this:
Code:
//Create

/// Init
oSurface = -1;


//Step

//Your Values can be optional. This is what i am currently using.
if (!surface_exists(oSurface))
{
   oSurface = surface_create(400, 400);
}
surface_set_target(oSurface);
draw_clear(c_white);

//This part is optional
draw_set_alpha(0.7);
draw_background_tiled(bg, 0, 0);
draw_set_alpha(1);

//Get objects for population on map
var numObjects = instance_number(par_minimap)

for ( var i = 0; i < numObjects; i++ )
{
   var obj = instance_find( par_minimap, i );
   var _px = obj_player.x
   var _py = obj_player.y
   with(obj)
   {
       draw_sprite( sprite_index, 1, x+200 - _px, y+200 - _py);
   }
}
surface_reset_target();



//Draw GUI

if (surface_exists(oSurface))
{
   //Your Values can be optional. This is what i am currently using.
   draw_surface_stretched( oSurface, 0, 60, 200, 200 );

   var old = draw_get_color();

   // Get underlay color.
   draw_set_color(c_white);

   //Your Values can be optional. This is what i am currently using.
   draw_rectangle( 0, 60, 200+0, 200+60, true);

   draw_set_color(old);
}
and I was wondering if there was a way to make it look at tiles. I used objects on the walls so they're solid and allow for particles, but I stretch the objects to cover the entirety of the area of the wall I make solid, to reduce the required resources, but this makes them only appear as a single square, and the wall objects are a solid color, since they're just invisible because I use tiles for the graphics of the walls. I'm still looking through the code, and it is working, even though it brings the framerate down to around 600fps after I changed the scaling on it to scale with the resolution and aspect ratio, but this has been the closest thing to a proper minimap I've found, so far, and 600fps is still acceptable.


Mostly, I'm not sure how to check for a tile like you can check for an object. I found that there's a tile_find function, but can't find information on it in the manual and the game doesn't give the little tips on it like it does with other functions.
I found this:
Code:
var tiles = tile_get_ids();
for (var a = 0; a < array_length_1d(tiles); a++)
    {
    draw_background_part(tile_get_background(tiles[a]), tile_get_left(tiles[a]), tile_get_top(tiles[a]), tile_get_width(tiles[a]), tile_get_height(tiles[a]), tile_get_x(tiles[a]), tile_get_y(tiles[a]));
    }
which adds the tiles to the minimap, but they don't move when I move around, as the objects do, though I did get the tiles to be layered under the objects, as they're supposed to be, but this was a simple fix that was done setting the loop that deals with the tiles to process before the loop that deals with the objects.

I've also adjusted the minimap so the displayed region will be around the cursor's position, rather than the player, since it's more suiting to the game I'm making and allows for a smaller zoom. This doesn't mean I've figured out how to make the tiles inside the minimap move, though; that's something that still needs to be done.
 
Last edited by a moderator:
S

Shawn

Guest
Okay, now that I'm not distracted by some of the news things I was watching, I took another look at the code and got the tiles working how I want. I'll edit this post with the finalized code I'm using to get everything done, as soon as I rename some variables and add comments to stuff.


EDIT:
Okay, first off, I'll include the code I wrote for scaling the game to match any aspect ratio and resolution, since the use of the minimap is in the GUI and my code for scaling is automatically adjusting the GUI's size. I haven't tested the minimap's code without my code for scaling the GUI, so I don't know how different it would be without it.

All of this goes in an object's create_event. Just make sure the object is the first thing to load, is always present in the room, and make sure there's only one of those objects. I suggest making a Major_System_Controller object that's set to persistent, so it only needs to be loaded a single time. By setting the object to persistent, you can load it in a different room, then immediately switch to the next room after the object is loaded.
Code:
globalvar Minimap_Width_Limit;
    Minimap_Width_Limit = 0;

globalvar Minimap_Height_Limit;
    Minimap_Height_Limit = 0;

This part goes in the Major_System_Controller object's step_event
Code:
///Adjust the game's view so there's no texture stretching with resolution changes
//Get the game's Height and Width and store them in variables
var Game_Window_Width = window_get_width();
var Game_Window_Height = window_get_height();

//Get the aspect ratio of the game's window and store it in a variable
//ex: 800/800 = 1 in 1:Y for Game_Aspect_Ratio_Width math
//ex: 800/800 = 1 in X:1 for Game_Aspect_Ratio_Height math
//ex: the math of both gets the X:Y
//IMPORTANT: Room view MUST be 1:1 ratio in room settings (make 1530*1530 res) - if you use a different 1:1 ratio view, make sure all the parts in this code that reference the 1530 view is changed to be the same as the view you set, or you could set a couple variables that store the room's set view, then use that variable in the place of where 1530 is in this code
var Game_Aspect_Ratio_Width = Game_Window_Width / Game_Window_Height;
var Game_Aspect_Ratio_Height = Game_Window_Height / Game_Window_Width;

//Calculate the width and height of the game view and store them in variables
var Game_View_Width = Game_Aspect_Ratio_Width * 1530;
var Game_View_Height = Game_Aspect_Ratio_Height * 1530;

//This is for aspect ratio scaling while maintaining some view at low widths
//Check if the width is greater than the height
if (Game_Aspect_Ratio_Width >= 1)
    {
    //Update the view with the stored width and room view height
    view_wview[0] = Game_View_Width;
    view_hview[0] = 1530;
    }
//Check if the height is greater than the width
else if (Game_Aspect_Ratio_Width < 1)
    {
    //Update the view with the stored height and room view width
    view_wview[0] = 1530;
    view_hview[0] = Game_View_Height;
    }

//Resize the GUI to scale it with the resolution
//The multiplier reduces the GUI size, with higher numbers making it smaller
display_set_gui_size(view_wview[0] * 5, view_hview[0] * 5);

//Fix interpolation getting disabled when the window is resized
//Enable_Interpolation is a variable I created for toggling interpolation on and off with the press of a key - if you plan on using interpolation, make sure you create a variable for it, then keep it set, otherwise resizing the window will disable interpolation
if (Enable_Interpolation == false)
    {
    texture_set_interpolation(false);
    }
else if (Enable_Interpolation == true)
    {
    texture_set_interpolation(true);
    }

Next, do stuff for the minimap.
First, create an object to act as the parent that enables the minimap; the object name I used in this is called Minimap_Controller_Parent. When that object is created, set that object as the parent object to any object you wish to view in the room. Note: This Minimap_Controller_Parent doesn't need to be placed inside a single room.
Code:
///Create variables for the minimap
//Create the Minimap_Surface variable
Minimap_Surface = -1;

//Create a variable to control if the minimap is turned on
Minimap_Enabled = false;

Code:
///Create the minimap
//Check if the minimap is enabled
if (Minimap_Enabled == true)
    {
    //Make sure the Minimap_Surface actually exists
    //Surfaces are volatile, so they can disappear and need re-creation
    if (!surface_exists(Minimap_Surface))
        {//You can adjust the view multiplier to determine the zoom of the room in the minimap
        Minimap_Surface = surface_create(min(view_wview[0] * 1.5,
             room_width), min(view_hview[0] * 1.5, room_height));
        }
    //Set the next steps of drawing to occur on the Minimap
    surface_set_target(Minimap_Surface);



    //Limit the minimap so it has a width boundary that the player can't see beyond
    //Make sure you keep the 1.5 multipliers the same as the surface_create view_wview[0] and view_hview[0] multipliers and keep the 0.75 multipliers equal to half the 1.5 multipliers
    //If you want it to follow the player, instead of the cursor, use the player object's x in place of mouse_x, such as Player.x -- it MUST specifically refer to the player object, due to the later use of with(Object_Find), which is used to find the objects and place them on the minimap
    if (surface_get_width(Minimap_Surface) >= room_width)
        {
        Minimap_Width_Limit = 0;
        }
    else if (view_wview[0] * 0.75 >= room_width - mouse_x)
        {
        Minimap_Width_Limit = view_wview[0] * 1.5 - room_width;
        }
    else
        {
        Minimap_Width_Limit = view_wview[0] * 0.75 - mouse_x;
        }



    //Limit the minimap so it has a height boundary that the player can't see beyond
    //Make sure you keep the 1.5 multipliers the same as the surface_create view_wview[0] and view_hview[0] multipliers and keep the 0.75 multipliers equal to half the 1.5 multipliers
    //If you want it to follow the player, instead of the cursor, use the player object's y in place of mouse_y, such as Player.y -- it MUST specifically refer to the player object, due to the later use of with(Object_Find), which is used to find the objects and place them on the minimap
    if (surface_get_height(Minimap_Surface) >= room_height)
        {
        Minimap_Height_Limit = 0;
        }
    else if (view_hview[0] * 0.75 >= room_height - mouse_y)
        {
        Minimap_Height_Limit = view_hview[0] * 1.5 - room_height;
        }
    else
        {
        Minimap_Height_Limit = view_hview[0] * 0.75 - mouse_y;
        }

    //Add some transparency - I suggest leaving the alpha at 1, so there's no transparency; this will be changed when the minimap is drawn in the draw_gui event
    //Also, set a background to the sections of the minimap that don't have anything to draw
    draw_set_alpha(1);
    draw_background_tiled(Black_Space_256, 0, 0);
    draw_set_alpha(1);

    //Get the locations of tiles and draw them to the minimap
    var Tile_IDs = tile_get_ids();
    for (var Tile_Find = 0; Tile_Find < array_length_1d(Tile_IDs); Tile_Find++)
        {
        draw_background_part_ext(tile_get_background(Tile_IDs[Tile_Find]),
            tile_get_left(Tile_IDs[Tile_Find]), tile_get_top(Tile_IDs[Tile_Find]),
                tile_get_width(Tile_IDs[Tile_Find]), tile_get_height(Tile_IDs[Tile_Find]),
                    min(tile_get_x(Tile_IDs[Tile_Find]), tile_get_x(Tile_IDs[Tile_Find])
                  + Minimap_Width_Limit),
                        min(tile_get_y(Tile_IDs[Tile_Find]), tile_get_y(Tile_IDs[Tile_Find])
                      + Minimap_Height_Limit),
                            tile_get_xscale(Tile_IDs[Tile_Find]),
                                tile_get_yscale(Tile_IDs[Tile_Find]), c_white, 1);
        }

    //Get the locations of objects containing and draw them to the Minimap_Controller_Parent
    var Object_IDs = instance_number(Minimap_Controller_Parent);
    for (var Object_Count = 0; Object_Count < Object_IDs; Object_Count++)
        {
        var Object_Find = instance_find(Minimap_Controller_Parent, Object_Count);
        with(Object_Find)
            {
            draw_sprite_ext(sprite_index, -1,
                min(x, x + Minimap_Width_Limit), min(y, y + Minimap_Height_Limit),
                        image_xscale, image_yscale, image_angle, c_white, 1);
            }
        }

    surface_reset_target();
    }

Code:
///Draw the minimap
//Make sure the Minimap_Surface exists before trying anything, to prevent crashing
if (surface_exists(Minimap_Surface))
    {
    //Draw the minimap at the desired x and y locations
    //You can change the transparency of the minimap to a variable for in-game settings
    draw_surface_stretched_ext(Minimap_Surface, 100, 250, min(view_wview[0], room_width), min(view_hview[0], room_height), c_white, 1/*This is the transparency that can be changed for a variable*/);

    var Previous_Color = draw_get_color();

    //Set the border color - remove this when adding a fancy sprite border
    draw_set_color(c_white);

    //Create a border at the desired x and y locations
    //Remove this when adding a fancy sprite border
    //If you want to keep this, since an automatically scaling minimap that can change its aspect ratio doesn't do so well with an image, you can adjust the transparency of the border of the minimap by using draw_set_alpha() before the rectangle is drawn, and you can also tie this to a variable - just make sure you also add draw_set_alpha(1); after the rectangle is drawn, or it may conflict with other things
    draw_rectangle(100, 250, min(view_wview[0] + 100, room_width + 100), min(view_hview[0] + 250, room_height + 250), true);

    draw_set_color(Previous_Color);
    }

Finally, add a toggle for the minimap
Code:
///Toggle the minimap
if (Minimap_Enabled == true)
    {
    Minimap_Enabled = false;
    if (surface_exists(Minimap_Surface))
        {
        surface_free(Minimap_Surface);
        }
    }
else if (Minimap_Enabled == false)
    {
    Minimap_Enabled = true;
    }

Also, yes, the framerate will take a sizable hit, as you can see when you toggle the minimap on and off, but the tests I've run still have the game running around 150-200fps, despite having thousands of particles on the screen. Additionally, make absolutely sure the object you're attempting to display ALWAYS has a sprite, even if it's invisible, otherwise it'll crash the game; there might be a way to avoid this, but I'm not sure how.
 
Last edited by a moderator:
Top