Super Mario Bros. Growing Vines in GameMaker: Studio

Since creating this blog - which has unfortunately seen more active days - I wanted to make tutorials exclusively for it. Providing Game Maker: Studio resources to developers is not a new ambition of mine as it's something I have been doing for nearly two years now on the YoYo Games Marketplace and Itchio. However, this tutorial-in-a-blogpost style is new to me, but I feel has potential as I'm not limiting myself to just code comments and can include images, .gifs, videos, and builds.

I decided to make this first tutorial a simple one suited towards beginners, more or less to test the waters of this platform. Today, I'll be showing you how to make growing vines as seen in the original Super Mario Bros. Below is a .gif of what we'll be making. Please note that all graphics used in this tutorial are property of Nintendo and are used for educational purposes only.

tapping question mark blocks to make vines appear

We will be using three objects (vine, brick, question-mark block), each with corresponding graphics that are 16x16 pixels. You can download the graphics, and the background image, here. Before we jump into the code, let me explain exactly how we'll approach spawning and growing vines. 

When a user clicks on a question-mark block, we'll spawn a vine object behind it at its coordinates. The vine object moves upwards, and when it has moved 16px vertically (its sprite height), it spawns a new vine object below it (again, inside the block). When a vine comes in contact with a brick, it will stop moving as will any vines below.

First, let's import all the graphics.

The question-mark block sprite (which I've named sBlock out of preference) has two frames: the second of which will be shown after it has spawned a vine. Similarly, the vine (sVine) has two frames. The first indicates the top of the vine and the second is used for the remaining segments. Lastly, the brick (sBrick) gets only one frame.

Now, let's get coding!

Create a new object for the block sprite. I'll go ahead and name it oBlock for consistency. Because the sprite has two frames and we don't want it to be animated, we'll go ahead and set image_speed to 0 in the Create Event.

image_speed = 0;

In the Step Event, we'll want to create a vine when clicked, but only if the object hasn't spawned one already.

if (mouse_check_button_pressed(mb_left) && collision_point(mouse_x, mouse_y, id, false, false) && image_index == 0) {
    image_index = 1;
    instance_create(x, y, oVine);
}

The function mouse_check_button_pressed() returns whether or not its parameter mb_left (left mouse button) is pressed. We want to pair this with the collision_point() function which to determine if the mouse is over the instance (id). The last two parameters of this function determine whether or not we want to use precision-checking (not necessary as the block graphic is a square) and whether or not the instance calling this function should be excluded from the check (it shouldn't -- we want to click on the object itself). Conversely, one could use the function point_in_rectangle() to determine if the mouse is within the bounding box of the block. A mouse click and collision check together essentially replicate a Mouse Left Pressed Event. Finally, we add the check "image_index == 0" to only spawn the vine if the sprite's first frame is being rendered. If the criteria is met, the object draws the sprite's second frame (which now invalidates the spawn check) and creates a vine object, oVine, at its coordinates.

That's it for the block object

Now, let's make a brick object, oBrick, which will stop a vine if one collides into it. No code is necessary, but if you expand upon this tutorial to implement it into a platformer of yours, you may want to make it solid so the player can stand on it.

Last but not least, let's program the vine object. We'll need to set some variables in the Create Event.

image_speed = 0;
depth = 1;          // renders the vine object behind the block from which it spawns
can_move = true;    // whether or not the vine is allowed to move vertically
spawned = false;    // whether or not the vine has spawned another vine below it

The Step Event is a little more complex, but let's go through it step-by-step.

var above = instance_place(x, y - sprite_height, oVine);

Using the instance_place(...) function, we are able to reference a particular object based on their position as it returns the object id, if it exists. We set temporary variable above to this. If there is a vine object above us, as indicated by the "y - sprite_height", we are able to call it using above.

if (above != noone) {
    if (above.can_move == false) {
        can_move = false;
    }
}

Before we reference above we need to make sure we actually can, using a check to determine if it does not equal no one (or, if it equals someone). For instance, the top-most vine does not have any more vines above it, meaning that above will be undefined for that particular instance. If the vine object directly above us is not able to move as per can_move, stop us from moving as well.

if (place_meeting(x, y, oBrick) || y <= -sprite_height || (place_meeting(x, y, oBlock) && spawned)) { 
    can_move = false;
}

There are three circumstances in which a vine will be unable to move vertically: if it touches a brick (using place_meeting()), if it goes out of the room and its y value is 0 minus its sprite height or less, or if it collides into a question-mark block only after it has moved out of the one it was created in (and has thus spawned a new vine).

if (can_move) {
    y -= 2;
    if (y % sprite_height == 0 && !spawned) {
        spawned = true;
        var inst = instance_create(x, y + sprite_height, oVine);
        inst.image_index = 1;
    }
}

If can_move is set to true, the vine object is able to move vertically by 2px. Ensure that the sprite_height can be evenly divisible by this amount. Next, we check if the vine object has moved vertically its sprite_height (i.e. the object is 16px less than its vertical spawn position). This code will only work if objects are placed on a grid the size of the sprite. This line can be replaced with:

if (y <= ystart - sprite_height && !spawned) {

where ystart is a built-in GM variable which is set to the y-coordinate where the instance is created. Similar to the check in oBlock to determine if the image's index was 0, we want to check if we spawned a vine. If not, create a vine and set spawned to true. You'll also notice that we set variable inst to the function instance_create(...). Like spawninst is now equal to an object id. We can now set this instance's frame to 1.

invisible blocks showcase how exactly the vines spawn

By making the question-mark blocks invisible, it's much easier to comprehend what's going on and when exactly objects spawn.

Aaand that's it! You can download the source here. Thanks for reading my first blog post tutorial and let me know how I can improve. Hope you learned something!

GameMaker-related posts mailing list