Make a Mini-Map Like GTA in GameMaker

Hello there! In this tutorial, you’re going to learn to make a minimap like the ones seen in GTA:

Image result for gta 3 minimap

So let’s get started!



Sprites


First of all, you need a complete map of your room. Since I did this from scratch, I took this screenshot from Google Maps as an example:

1.PNG

So this will be the complete map of my room. Now, you need to decide on a divider number, that will affect the size of the minimap compared to the real map. I chose 5 – so say if the map’s width is 2000, the minimap’s complete size will be 2000/5 = 400.

So, import the map of your room into GMS as a sprite, which I’ll name “spr_minimap“, and divide its size by the divider you set before. So if your map’s size is 4000×2000 and the divider is 5, the minimap’s size should be 800×400.

2.PNG
spr_minimap, the map of my room with its size divided by 5

Then click on Edit Image to open the image editor. Here, create another layer and draw your minimap there. (If you’re using GM:S 1, create another sub-image and use the onion-skinning feature to see the base image – only in professional versions. If you don’t have it, then just draw over it).

Here’s my minimap progress:

pjimage.jpg

Lastly, you need to create an icon that will display the position of the player on the minimap – let’s name it spr_player_icon. This is what I created:

7.PNG

Make sure its origin is set to middle-center. Now let’s move on to…



Objects


Now I need to create an object, and I’ll name it obj_minimap. Add the Create event, and add this code there:

//map properties
map_divider = 5;

map_player_x = obj_player.x/map_divider;
map_player_y = obj_player.y/map_divider;

//map surface
map_width = room_width/map_divider;
map_height = room_height/map_divider;

map_surface = surface_create(map_width, map_height);

map_divider is the divider we set at the start of this tutorial. map_player_x and map_player_y store the player’s position on the minimap, which is just the real player’s position divided by map_divider.

obj_player is my player object. If yours is named something else, use that name.

map_width and map_height are the total width and height of the minimap, which are just the room width and height divided by map_divider. So you see, the minimap is just a smaller version of our room, with just the widths, heights, and positions divided by a constant divider.

map_surface is the surface the whole minimap is drawn on. If you don’t know how surfaces work, read this. I’m setting the size of the surface to that of the minimap.

Next, I need to make sure that the player position is constantly being updated. So for that, I’ll add the End Step event and add this code there:

//map player location
map_player_x = obj_player.x/map_divider;
map_player_y = obj_player.y/map_divider;

That’s the same code we had in the Create event for setting the variables. It just updates the player position on the map according to the real position of the player.

Next I’ll add the Draw Begin event and add this code there:

if (!surface_exists(map_surface)){ 
    map_surface = surface_create(map_width, map_height);
}

Surfaces tend to automatically get destroyed, so you need to have this fail-safe code in the Draw Begin event that checks if the surface exists, and if it doesn’t, recreates it.

Now I’ll draw the minimap to the surface. For that I’ll add the Draw event and here I’ll add this code:

//draw to map surface
surface_set_target(map_surface);
//draw minimap
draw_sprite(spr_minimap, 0, 0, 0);
//draw player icon
draw_sprite_ext(spr_player_icon, 0, map_player_x, map_player_y, 1, 1, obj_player.image_angle, c_white, 1);

surface_reset_target();

So first it sets the draw target to map_surface, meaning that everything after that will be drawn to that surface. Then I’m drawing the minimap sprite, spr_minimap, at 0, 0 in the surface.

Then I’m drawing the player icon at the player location on the minimap, and getting the player’s image_angle to rotate the icon. After that I’m resetting the draw target to the default game surface – you should always do this after you’re done drawing things to a surface.

So now that we’re done drawing the minimap onto the surface, let’s draw a part of the minimap onto the screen. For that, I’ll use the Draw GUI event and add this code there:

//draw map on screen
var margin = 32;
var map_size_x = map_width * 0.6;
var map_size_y = map_height * 0.6;
var map_x = map_player_x-map_size_x/2;
var map_y = map_player_y-map_size_y/2;

map_x = clamp(map_x, 0, map_width-map_size_x);
map_y = clamp(map_y, 0, map_height-map_size_y);

draw_surface_part(map_surface,  map_x, map_y, map_size_x, map_size_y, 
    margin, window_get_height()-map_size_y-margin);

margin is the distance between the edges of the window and the minimap. Then I’m creating map_size_x and map_size_y, which are the horizontal and vertical sizes of the minimap that will be drawn to the screen. I want it to be 6/10th of the size of the whole minimap, so I’m multiplying the map_width and map_height with 0.6. We can call this the “view size”.

Then map_x and map_y are storing the position inside the minimap surface from where it will be drawn. Next they are being clamped to a limit that is from 0 to the total size minus the view size, so that the view stays inside the surface.

Then a part of the surface is being drawn to the screen. In the draw_surface_part() function, the first argument is the surface that is drawn, the next two are the positions from where the surface is drawn, the next two are the sizes of the view, and the next two are the positions where the surface is drawn on the screen.



Testing


Now place obj_minimap inside your room and run the game!

2.gif

The minimap should follow your player object well.

But… what if we need a circular map? We can do that as well – using blend modes!

Blend modes can be hard to understand if you’re new to them. Basically, using blend modes you can control what is being drawn. So I will use them to only draw the minimap on a circle sprite.



Sprites


First of all, I need to create a white circle sprite for the minimap. I’ll set its diameter to half of the whole minimap’s height – because I want half of the minimap to be visible at one time. Since the height of my minimap is 170, this circle is going to be 85×85.

9.PNG
spr_circle

Now let’s move on to coding.



Objects


First I need to create another surface inside obj_minimap‘s Create event.

minimap_surface = surface_create(85, 85);

So this is the surface where the minimap will be drawn, instead of the screen. We will use this surface for making the minimap appear circular, and then draw this surface onto the screen.

Since I created a new surface, I also need to add its fail-safe code in the Draw Begin event:

if (!surface_exists(minimap_surface)){ 
    minimap_surface = surface_create(85, 85);
}

Now, open the Draw GUI event, and change all of the code with this:

//draw map to surface
var map_size_x = surface_get_width(minimap_surface);
var map_size_y = surface_get_height(minimap_surface);
var map_x = map_player_x-map_size_x/2;
var map_y = map_player_y-map_size_y/2;

map_x = clamp(map_x, 0, map_width-map_size_x);
map_y = clamp(map_y, 0, map_height-map_size_y);

surface_set_target(minimap_surface);

draw_sprite(spr_circle, 0, 0, 0);

gpu_set_blendmode_ext(bm_dest_color, bm_zero);
draw_surface_part(map_surface, map_x, map_y, map_size_x, map_size_y, 0, 0);
gpu_set_blendmode(bm_normal);

surface_reset_target();

Now, the map view size is set to the minimap_surface‘s size.

After setting the surface to minimap_surface, I’m drawing the circle sprite at 0, 0. Then I’m setting the blend mode so that it only draws on what is already there – and then I’m drawing the part of the surface at 0, 0. Then I’m setting the blend mode back to normal. So this will draw the map_surface on the circle only.

To understand how blend modes work, read this.

If you’re using GM:S 1, you’ll need to use draw_set_blend_mode() and draw_set_blend_mode_ext(). They were changed to gpu_set_blendmode in GMS2.

Move this code from Draw GUI to Draw.

We no longer need this in Draw GUI since we’re drawing this onto a surface and not on the screen, so it should go in the Draw event.

In Draw GUI, add this code:

//draw minimap surface on screen
var margin = 32;
draw_surface(minimap_surface, margin, 
    window_get_height()-margin-surface_get_height(minimap_surface));

So here, I’m setting the margin, and drawing the minimap_surface on the screen.



Testing


Now run the game:

3.gif
(The GIF messed up the minimap)

You can see that the minimap appears circular now!



Conclusion


This way, you can create a minimap for your open world game. If you want to draw more points on the minimap, just get their x/y locations in the End Step event, divide them by the divider and draw icons at their places!



Click here to download this project (GMS2)


Hope this tutorial helped you! If you have any further questions or doubts, join my Discord server (no sign-up required) and you can get all the help you want there, for free. You can also find me there (username: matharoo).

Check out my pop-up text box asset on the marketplace!

Be the first one receive updates on new & upcoming tutorials by liking our Facebook page!

See you, and happy dev’ing!

 

 

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s