GameMaker: Studio

GameMaker: Studio

26 ratings
Fun with Surfaces: Today, Minimap
By Scorcher24
Surfaces are key to success in GameMaker. It allows us to use advanced features, such as minimaps.
I am going to show you how to do one.
   
Award
Favorite
Favorited
Unfavorite
Prerequesites
You need an understanding of GML. If you are still using Drag and Drop Items, you might not understand this tutorial and want to dive into programming first.

Still here? Good, grab a cup of coffee and some cookies.

Next you are going to need one or two different backgrounds, an enemy sprite and a player sprite.
I used sprites from this pack: http://opengameart.org/content/space-shooter-redux
Consider donating to Kenny if you like his art, he does all this stuff for free.

All set? Good, now onwards, my minions, to the tutorial!
Creationism
Allright, the first section should be pretty straightforward.

  • Create one or two different backgrounds, depending on your gusto. I use one bright and one dark background.
  • Create a sprite, name it sprEnemy and load one of the sprites from the pack.
  • Create a sprite, name it sprPlayer and load (a different) one of the sprites from the pack.
  • Create objects for the previously created sprites (they don't need to do anything, but you can make the player move if you want)
  • Create a room.
    • Set it's height to 720 and it's width to 2560 in the settings
    • Switch to views
    • Make the room follow the player
    • Set "View in Room" to 1280x720
    • Set "Viewport on Screen" to 1280x720
  • Add one instance of the player and some random number of enemies randomly to the room.
  • Set the lighter background for the room.

Fun with Parents
Parenting is pretty much polymorphism in GM:S. So if you set a parent, all events in that parent are transferred to the child. Or, you can make this object the parent of all objects that need to be drawn on the minimap and you can walk them without having to search for each object that you want on your minimap. This is quite handy.

So create an object, call it objShowMiniMapParent and assign it as parent to objEnemy and objPlayer.
Quick looks are the best looks
So we do not want our player having to stare at the minimap all the time. You want to have a quick look and he knows what is happening. Since we are using a parent to walk through all objects, we do not know what kind of object it really is. If it is the player or an enemy.
For this reason, we use 2 new images:



Now double click your player sprite in GameMaker. Go to "Edit sprite" and in the File menu, click on "Add from File". Now GameMaker will complain that this file has not the same size.
Answer as shown here:



This will ensure your sprite will not get cropped and the circle is placed on a transparent background.
Later in the code, we are going to use this to display the circles on the minimap.

You should have it like this now:

But, if you would start the game right now, the game would "play" it as animation.
That is why we need to add some code to the player object and the enemies.
Add a create event to both of them and add this code:

image_speed = 0; image_index = 0;

Setting image_speed to zero stops the animation and image_index set's the normal sprite of your space ship as current sprite, provided it is 0, whch it should be since you added the circle after the normal sprite, right?
Coding Time!
Now we are going to create the minimap. Create an object and name it objMinimap. I always like to add a sprite with an ugly background and some text on it to it, so I find it better in the editor. But that is up to you. Place that object in the level.

Now, coding time. We are going to use a surface to draw our minimap. So first, we create a "Create Event" and add this code:

/// Init oSurface = -1;

Next, we are going to create the surface with the exact size of our room and draw the content of our level to this surface. Create a new script in the step event for this code:

/// Create and populate Surface /* If the surface does not exist, we create it. Surfaces can be discarded in memory at any time, so we need to always check this before we use it. */ if (!surface_exists(oSurface)){ oSurface = surface_create(room_width, room_height); } // Set the surface as texture taret surface_set_target(oSurface); // Clear it with black draw_clear(c_black); /* Draw the second, dark background. You can leave this out if you prefer the minimap to have a black background or you can also draw the same background as the real room, but I don't like that. However, it is up to you. */ draw_background_tiled(background1, 0, 0); // Here we find out how many objects exist that want to be drawn on the minimap. var numObjects = instance_number(objShowMiniMapParent) // Here we loop through all those objects from 0 to the max number of objects. for ( var i = 0; i < numObjects; i++ ) { var obj = instance_find( objShowMiniMapParent, i ); with(obj){ // Remember that we have 2 images inside our sprites? This code draws the second one. draw_sprite( sprite_index, 1, x, y ); } } // Tell GM:S to stop drawing to this surface. surface_reset_target();
Drawing the surface
This part is easy peasy. We need to draw the surface to our screen. Add a "Draw GUI" Event to objMiniMap and add this code:

/// Draw Surface to Screen // Check for surface before drawing, it could be dead already. Should not happen, but can. if (surface_exists(oSurface)) { // Draw the surface first. But, since this surface is quite big, we are going to scale it down a bit and draw it to the top left on the screen. draw_surface_stretched( oSurface, 40, 40, room_width/8, room_height/8 ); // Save the old color that was set var old = draw_get_color(); // Get us a nice red draw_set_color(c_red); // Draw a red rectangle around it, so we can even better distinguish it from the actual room. draw_rectangle( 40, 40, room_width/8+40, room_height/8+40, true); // Set the old draw color draw_set_color(old); }

As you can see, using the surface is pretty straightforward and easy.
And that is what it looks like:

Conclusion
There are easier ways to add minimaps and you can actually use views for that. But in my opinion, that is just plain ugly and lazy. This way we have a nice minimap that can be distinguished from the actual level and gameplay and you only need a quick look to see what is going on.
You can use this technique for space games, platformers, RTS, does not matter. The approach can always be similar. Of course, if you have really a lot of objects, this might cost significant performance!

But it should be good enough for your average household 2D Game. Hope you have fun using this tutorial in your game.

If you want to save memory, scale down the map when you create it, by dividing the room size with e.g. 3 or 4. Don't forget to adjust the coordinates of objects too, by dividing them through the same number.
Downloads
As always, can you download this Tutorial as premade GMZ to import it into GM:S and as Workshop Item:

Workshop
GMZ [drive.google.com]
9 Comments
The Winter Bud 1 Dec, 2019 @ 5:41am 
[quote]There are easier ways to add minimaps and you can actually use views for that. But in my opinion, that is just plain ugly and lazy. [/quote]decent tutorial on surfaces but as you stated it's much easier with views and as for your opinion, just because it's the easy way doesn't make it lazy. The shortest distance between two points is a straight line not a lazy line.
Scorcher24  [author] 6 Apr, 2016 @ 11:27pm 
@BOYCOTT S-T-E-A-M! Thanks for the praise and the error report. I fixed that.
BOYCOTT S-T-E-A-M! 6 Apr, 2016 @ 7:05pm 
An excellent guide. I haven't done much work with surfaces but this is a nice introduction. A minimap is a great way to show off surfaces and what they can be used for and is also a fairly common component in modern games. The tutorial also leaves a nice framework, especially if you added movement for the player, to create a starting point for a simple game project. Very well done.

Only criticism would be that under the "Coding Time!" section the second code block, starting with "/// Create and populate the surface" doesn't show where to place it and gives the impression it goes in the "Create Event" like the initialization before it. It works fine in the base tutorial, but if you added in movement you'll be left with a static minimap. If that code is instead placed in the "Step Event" you'll have a minimap that updates as expected while moving about.
2IndieDev. 19 Feb, 2015 @ 4:54pm 
Idk their fixed I thought you did it haha
Scorcher24  [author] 19 Feb, 2015 @ 4:08pm 
I didnt do anything
2IndieDev. 19 Feb, 2015 @ 4:04pm 
Fixed your great man Thanks
:Lord_Fist:
Scorcher24  [author] 18 Feb, 2015 @ 8:11pm 
Seems like all pictures from all my guides and workshops are gone. I reported it to Valve.
Let's see if they can fix it.
Scorcher24  [author] 18 Feb, 2015 @ 8:08pm 
No idea what is going on there...
2IndieDev. 18 Feb, 2015 @ 7:36pm 
Your pictures are broken