Dynamic Collidable Object Creation

***This tutorial is for GameMaker 8.1 and earlier versions. Many of these functions are obsolete in GameMaker:Studio***

I spend a lot of time just playing around in Game Maker, creating snippets of game play and testing out ideas. I have accumulated a lot of these, but I actually haven’t used most of them in a game. This is partly due to the fact that I enjoy the discovery process so much, that once I have achieved my goal, I am pretty much done with it. Recently, I asked myself, why am I wasting all of this knowledge? Maybe someone out there can put this to good use. Therefore, I have decided to share some of these experiments, starting with Dynamic, Collidable, Object Creation.

It sounds pretty exciting, doesn’t it? But what exactly is it that we are making here? The design premise I had was fairly simple: Draw rectangles that  have collision. It seemed simple until I tried to build it. That was when I realized that the actual design is actually a bit more complex: Draw a rectangle, create a sprite, create an object, apply the sprite to the object and add solidity.

I will say that this took me a lot longer than I thought to figure this out as it requires some of Game Maker’s more underutilized functions, such as object_set_sprite(). Before we get into that, however, I need to briefly talk about the player character and controls.

Player Controls

The character used in this example is a simple square, 32 x 32 pixels. It’s controls are basic and are the ones I generally use for quick testing. It is a simple control system that breaks movement down into three stages: Forecast, Move, Confirm. In the Forecast stage (Begin Step), I check if the player is capable of moving by using the place_free function and a variable.

scr_Controls_Begin

// Forecasting
if place_free(x-8, y) { left = 1;} else { left = 0; hspeed = 0;}
if place_free(x+8, y) { right = 1;} else { right = 0; hspeed = 0;}
if place_free(x, y-8) { up = 1;} else { up = 0; vspeed = 0;}
if place_free(x, y+8) { down = 1;} else { down = 0; vspeed = 0;}

Then the Move stage (Step Event), I move the player and set the variable to 2.

scr_Controls_Step

if left == 1 && keyboard_check(vk_left) {hspeed = -8; left = 2;}
if right == 1 && keyboard_check(vk_right) {hspeed = 8; right = 2;}
if up == 1 && keyboard_check(vk_up) {vspeed = -8; up = 2; }
if down == 1 && keyboard_check(vk_down) {vspeed = 8; down = 2;}
if keyboard_check(vk_nokey) {hspeed = 0; vspeed = 0;}

Finally, the Confirm stage (End Step), I double check the collision and snap the player to any solid surface that it is near. This is to ensure the player appears tight to the walls.

scr_Controls_End

if !place_free(x-8, y) { move_contact_solid(180, 8); left = 0;}
if !place_free(x+8, y) { move_contact_solid(0, 8); right = 0;}
if !place_free(x, y-8) { move_contact_solid(90, 8); up = 0;}
if !place_free(x, y+8) { move_contact_solid(270, 8); down = 0;}

This is by no means a prefect system, but it works great for experiments such as this.

Drawing Collidable Rectangles

Now that we have a character moving around nicely, it’s time to draw some boxes! Let’s start by creating a controller object, which I am going to call obj_DrawBoxFactory. This object doesn’t have a sprite attached and will be responsible for creating the rectangles.

To start, we need to initialize a variable in the Create Event

setPoint = false;

Next we need our main script, which I will call scr_SpawnBox which will be placed in the Draw Event. Our first step is to just draw a rectangle. There is a lot of code in this script, but we will walk through it to hopefully clarify what is going on.

Drawing the Rectangle

To help with the readability, we are actually going to draw a rectangular outline while the player is dragging the mouse across the screen. The code below, you can see that we check for the mouse button to be pressed which grabs the mouse’s x and y coordinates and changes our setPoint variable to true. This would be the first corner of the box.

//Initial starting point of box
if mouse_check_button_pressed(mb_left) {
    origX = mouse_x;
    origY = mouse_y;
    setPoint = true;
}

When setPoint is true, a yellow rectangle is drawn, starting at the original mouse location, to wherever the mouse is currently.

//Draw an outline of a rectangle in real time
if setPoint == true {
    draw_set_color(c_yellow);
    draw_rectangle(origX, origY, mouse_x, mouse_y, true);
}

Creating the Object

The rest of the code, as seen below, is dependent on the player releasing the mouse button. Once they have done that, we grab the last mouse location and set it to be our myWidth and myHeight.

//Create the box
if mouse_check_button_released(mb_left) {
    //Set the end points
    myWidth = mouse_x;
    myHeight = mouse_y;

We will use the width and height to compare against our original location. The reason we need to do this, is we need to know which way the player drew the box. In order to create a sprite, we need the upper left corner and the width and height. What would happen if they started in the bottom left corner? Upper right? We would be putting in the wrong information and the sprite would not be displayed as drawn. This code simply compares the two sets of coordinates and choose which one is the top left (tlx / tly) and the bottom right (brx / bry).

    if myWidth > origX
    {
        tlx = origX;
        brx = myWidth - origX;
    }
    else
    {
        tlx = myWidth;
        brx = origX - myWidth;
    }
    if myHeight > origY
    {
        tly = origY;
        bry = myHeight - origY;
    }
    else
    {
        tly = myHeight;
        bry = origY - myHeight;
    }

Next, we set the color of the rectangle and draw it with the set coordinates. This replaces the outline with a solid block of blue.

    //Set box color
    draw_set_color(c_blue);
    draw_rectangle(origX, origY, myWidth, myHeight, false);

To create a sprite, we are going to use one of the underused functions sprite_create_from_screen(). As previously mentioned, it requires the upper left corner ( tlx, tly ) and the width and height ( brx, bry ). After that, it asks for whether we want to remove the background (false), whether we want anti-aliasing or smoothing (false), and the sprites origin (0,0). Using this function returns the sprite’s ID, which we capture in the newSprite variable.

//Create a new sprite from the area on screen where the box should be created.
    newSprite = sprite_create_from_screen(tlx, tly, brx, bry, false, false, 0, 0);

Now that we have a sprite, let’s create that object. This requires three functions: object_add which creates a new object, object_set_sprite which allows us to place a sprite on the object, and finally, we are setting the object itself to be solid by default.

//Create a new object
    newObj = object_add();
    object_set_sprite(newObj, newSprite);
    object_set_solid(newObj, true);

Important note here, we have created an object, but we have not created an instance of the object. So let’s wrap this up by adding it to the scene and turning our setPoint variable off.

//Create an instance of object
    instance_create(tlx, tly, newObj);
    setPoint = false;
}

Recap

Just in case you had trouble following along, here is the entire piece of code:

scr_SpawnBox

//Create the box
if mouse_check_button_released(mb_left) {
    //Set the end points
    myWidth = mouse_x;
    myHeight = mouse_y;

    if myWidth > origX
    {
        tlx = origX;
        brx = myWidth - origX;
    }
    else
    {
        tlx = myWidth;
        brx = origX - myWidth;
    }
    if myHeight > origY
    {
        tly = origY;
        bry = myHeight - origY;
    }
    else
    {
        tly = myHeight;
        bry = origY - myHeight;
    }

    //Set box color
    draw_set_color(c_blue);
    draw_rectangle(origX, origY, myWidth, myHeight, false);

    //Create a new sprite from the area on screen where the box should be created.
    newSprite = sprite_create_from_screen(tlx, tly, brx, bry, false, false, 0, 0);

    //Create a new object
    newObj = object_add();
    object_set_sprite(newObj, newSprite);
    object_set_solid(newObj, true);

    //Create an instance of object
    instance_create(tlx, tly, newObj);
    setPoint = false;
}

Download the completed file

Conclusion

There you go! If you haven’t done this already, put this code in the Draw Event of our obj_DrawBoxFactory and place an instance of this and the player into a room and run it. You should be able to move the character around with the arrow keys, draw rectangles with the mouse, which become solid objects with collision. You now should understand how to create a sprite and object dynamically and add it to your game.

Hopefully this gives you some game ideas and I look forward to seeing what people can do with it.

Leave a Reply