Wednesday 15 August 2012

Thanks

That was it guys!

I have truly learned a lot while making this game in Game Maker, I hope you have as well! Keep in mind this was my first venture into programming and Game Maker in general. If I have done things inefficiently please forgive me. If you find any bugs I haven't come across, please let me know in the comments and I will take a look at them.

Now that you have programmed all these things don't forget to make a nice challenging level for you and your friends to play through!

Thanks for taking this educational programming journey with me! Good luck on your future programming and/or Game Maker endeavors!

Post 07 - Collect & Score

No platformer is complete without collectibles. In this post we will create a collectible object to be placed around the level, a HUD object which will count how many collectibles you have collected and a level exit which only becomes available after a set amount of collectibles have been collected.

THE COLLECTIBLE
We'll start by creating a new sprite and object voor the collectible. I've named mine obj_coin. This collectible will work slightly different then you might be used to. For it to be 'picked up' both players must have collision with it at the same time. Collision Events only allow collision with one object, so we make a Step Event in the collectible object and check for collision with code. If both players have collision with it, it will disappear. We use the following bit of code for this.

if collision_rectangle(x-8,y-8,x+8,y+8,obj_char,0,0) && collision_rectangle(x-8,y-8,x+8,y+8,obj_char2,0,0)
{
    instance_destroy();
}

The above collision code works like this. First you give the four corners of the collision rectangle, then the object you want to check collision with, and then if precise is true and if notme is true. We draw a collision rectangle as big as the coin (in relation to the center of the coin it  draws the collision rectangle from x-8 to y-8 to x+8 to y+8) and check for the player1 object. Precise and notme are false. We do the exact same for player2 object. Place some collectibles in your test level.

THE HUD
Next we want our amount of collected objects to be displayed somewhere. For this we make a new object which will serve as a hud. I made it 32x32 and made it look like the image below. It's basically my collectible object with an equal sign next to it. I called it obj_hud. Place the hud object in your test level. Preferably somewhere in one of the upper corners.


We are going to count the collected objects in the hud object. So let's start off by defining collect_counter in the Create Event of the hud object and settings it's value to 0.

collect_counter = 0;

Next we want the counter to go up by 1 every time both players collide with a collectible. To do this we edit the above piece of code like this.

if collision_rectangle(x-8,y-8,x+8,y+8,obj_char,0,0) && collision_rectangle(x-8,y-8,x+8,y+8,obj_char2,0,0)
{
    obj_hud.collect_counter += 1;
    instance_destroy();
}

Now it will add 1 to the collect_counter of the hud object before being destroyed.

Our next step is to be able to see how many collectibles we have collected. To do this we will use a draw function. Draw functions can only be used in Draw Events, so we'll make a draw event in the hud object. Once an object has a Draw Event, the object itself must be drawn within this event, or else it won't be visible in the game. So in the Draw Event we type the following code.

draw_sprite_ext(spr_hud,0,x,y,1,1,0,c_white,1);

draw_text(x+20,y-10,collect_counter);

The first bit of code draws the hud object. It is the same piece of code we have used before. The second piece draws how many collectibles we have collected at position x+20 and y-10 from the hud object position. This position worked best for the hud object I draw, it might work out differently with yours. Play around with it a bit until you have a nice position.

THE EXIT
Next up we'll create an exit object. Mine looks like a gate and is called obj_exit. Place the exit somewhere in the test level. We want this exit to appear whenever a set amount of collectibles have been gathered. In my case 5. To do this we make a Draw Event in the exit object and use the next piece of code.

if obj_hud.collect_counter >= 5
{
    draw_sprite_ext(spr_exit,0,x,y,1,1,0,c_white,1);
}

This code checks if the collect_counter has reached 5. If so, it draws the exit in the same way we have drawn objects before.

Lastly we want the exit to show a message and how many collectibles you have collected. We do this by creating a Step Event in the exit object and using the same collision check code as we used before with the collectibles. Except now the collision rectangles are bigger because my exit object is bigger.

if collision_rectangle(x-16,y-16,x+16,y+16,obj_char,0,0) && collision_rectangle(x-16,y-16,x+16,y+16,obj_char2,0,0)
{
    show_message("GOOD JOB! You have collected "+string(obj_hud.collect_counter)+" coins!");
    game_end(); 
}

So if there is collision with both players it will show the above message. What is typed in between quotes will be shown as text in the message. In the string we show the collectible counter. Afterwards the game will close.

Great! You now have the basics of a sneak/platform game!

ASSIGNMENT: COUNT PLAYER DEATHS
Find a way to count the death of both players and show this amount at the end message.

Take a look at how I did it (including assignment answers) here.

Post 6 - Hiding

The game we are building wouldn't be a sneaking game (which it will be) if you wouldn't be able to hide. And this is exactly what we are going to do in this post. We are giving the player a way to hide behind certain objects so he can pass by enemies undetected. To start off let's create an object the players can hide behind.

CREATING THE OBJECT
Create a new sprite and the same way we made the ducking sprite but give it another color. Then make an object and link the sprite to it. Don't forget your naming conventions! My objects to hide behind is a crate, so I've called it obj_crate.

SNAPPING BEHIND THE OBJECT
We want the player to be able to hide behind this object. We'll do this by writing a piece of code which ensures that whenever the player ducks while in collision with a crate he will snap to the precise position of the crate and will not be killed by the enemy or his sightcone.

Let's start with the position snapping. For this we write the following bit of code in the crates Collision Event with player1.

if (obj_char.sprite_index = spr_char_low)
{
    obj_char.x = x;
    obj_char.y = y;
}

If there is collision between player 1 and the crate the code checks if the player sprite is the ducking sprite, meaning the player is ducking. If this is true the players x and y position are made exactly the same as the crate's x and y position. 

NOT DYING WHILE HIDING
Now that we've got the snapping down let's code that the players don't die by the sightcone or enemy when hiding behind a crate. We do this by first creating hide_status in the player's Create Event.

hide_status = false;

Then we set hide_status to true whenever the player is hiding behind a crate by editing the above code.

if (obj_char.sprite_index = spr_char_low)
{
    obj_char.x = x;
    obj_char.y = y;

    obj_char.hide_status = true;  
}
else
{
    obj_char.hide_status = false;
}

Next we edit the code in the enemy Step Event which kills the player whenever he touches the sightcone and include a check to see if the player is hiding or not. So now it checks the collision line, player collision with scone and hiding status before deciding whether to kill the player or not.

if (collision_line(x,y,obj_char.x,obj_char.y, obj_tile,1,0) < 1 && scone.char_collision = true && obj_char.hide_status = false)
{
    obj_char.destroy = true;
    scone.char_collision = false;
}
scone.char_collision = false;

And finally we edit the enemy Collision Event with player 1 (the piece of code you had to write on the last post's assignment) to include a check if the player is hiding or not. 

if obj_char.hide_status = false
{
    obj_char.destroy = true;
}
else
{
    obj_char.destroy = false;
}

Whenever there is collision between the enemy and the player this code checks if the player is in hiding. If not the player is destroyed.

We now have a fully functioning hiding mechanic!

ASSIGNMENT: CAN'T HIDE BEHIND SAME CRATE
Let's make our hiding mechanic a tad fancier. By editing the code in the crate's collision event with the players, make it impossible for both players to hide behind the same crate. Don't forget to add all the functions you've written above to player2 as well!

Take a look at how I did it (including assignment answers) here.

Post 5 - Enemy Sightcone

Because we are creating a sneaking game one of the main goals will be to stay undetected. To indicate when you are in or out of an enemy's sight we create a sightcone which we will attach to the enemy.

CREATING THE CONE
Let's start by actually creating the sightcone the same way we created other sprites and objects. Create a new sprite and make it 120x48. Make it look like the image below. Give it precise collision checking and set it's origin at x = 0 and y = 24 (left/middle). Give it an appropriate name.


ATTACHING THE CONE
Once the cone is created we can attach it to the enemy. We do this in the enemy's Create Event with the following code.

scone =  instance_create(x,y,obj_scone);

We have created scone (sightcone) at the x and y of the enemy and used the sightcone object. The sightcone is now attached to the enemy but will not turn with the enemy yet. For this we need the following piece of code in the enemy's Step Event.

scone.image_xscale = enemy_direction;

scone.x = x;
scone.y = y-8;

Because we are referring to scone from the enemy object, we write scone. infront of our code. So when we write scone.image_xscale we are talking about the xscale of scone and not the xscale of the enemy itself.

The image_xscale is linked to enemy_direction. Meaning if the enemy walks to the right (direction = 1) the scale of the scone will be 1 (original image, facing right). If the enemy walks to the left (direction = -1) the scale will be -1 and the image will be mirrored, facing left.

The scone.x = x and scone.y = y-8 position the scone according to the enemy x and y. So now the scone will be drawn 8 pixels above the enemy center.

Next create an object for it with an appropriate name and link the sprite to the object. This sightcone is quite large and it can be quite annoying if objects in the level are hidden behind it. This is why we will give it an alpha of 0.5 so we can see partly through it. To do this we must add a Draw Event to the object. In this Draw Event we write the following piece of code which draws the cone from scratch and gives the ability to edit it in various ways.

draw_sprite_ext(spr_scone,0,x,y,image_xscale,1,0,c_white,0.5);

In the brackets the following aspects of the image must be given: which sprite must be drawn, which subimage of the sprite must be drawn, x position, y position, x scale, y scale, rotation, color and alpha. If the color is set to white it means it will be shown as its original color as given in the sprite editor.

MAKING IT KILL
To make it more interesting we'll have the sightcone kill players straight away once they touch it. To do this we must first add a Create Event to the sightcone object and type in the following code.

char_collision = false;

We have now created char_collision and defined it as false when the cone is created. Next we create a
Collision Event in the sightcone object with player1 as the collision target. In here we type the following code.

char_collision = true;

Now we go to the enemy object's Step Event. Here we will decide what will happen if collision between player and sightcone is true. We do this with the following code.

if scone.char_collision = true;
{
    obj_char.destroy = true;
    scone. char_collision  = false;
}

This code is quite simpel. If scone collides with player1, set player1's destroy value to true and set collision to false. This last bit is important, if you don't set it back to false after the player has died, he will keep on dying because the collision value will still be true. Player1 doesn't have a destroy value yet though. In the assignment below you will set that value and actually make the player die.

We now have a working collision code (if you take in account the assignment below) except for one problem. What if the player has collision with the sightcone but there is a tile in between the player and the enemy? This should mean the player should not be seen by the enemy shouldn't it? To do this we use the following code.

collision_line(x,y,obj_char.x,obj_char.y, obj_tile,1,0);

This piece of code draws an imaginary line between a given x and y to another given x and y and checks if it collides with a certain object. It also needs to know prec and notme. Prec means precise and refers to if you want to check the precise sprite or the bounding box. Notme refers to if you want to check the for the item in which you have set the code as well. In our case we use the enemy's x and y and player1's x and y, check for the tile object, check the precise sprite (1 = true) and do not check for the enemy object in which the code is made (0 = false).

Now we'll use this code in combination with our previous destroying code.

if collision_line(x,y,obj_char.x,obj_char.y, obj_tile,1,0) < 1 && scone.char_collision = true
{
    obj_char.destroy = true;
    scone.char_collision = false;
}
scone.char_collision = false;

This is the exact same as our code before except now it checks if the collision_line check is false. So if there is no collision with a tile and the collision line AND the player has collision with the sightcone, the player will be destroyed and the sightcone's player collision will be set to false. We have also added a second line which sets collision with player1 to false. This one is to prevent the following scenario: Player 1 is behind a tile. So there is no line of sight but there is collision. Because there is collision scone.char_collision is set to true. If the player would later move away when there is no longer collision but there is line of sight, the player will still be destroyed.

ASSIGNMENT: ACTUALLY DESTROYING PLAYERS
So we see the above code changes the destroy value in obj_char (player1) to true but obj_char does not actually have a destroy value yet. With the things you have learned create a destroy value for the player and make sure when it is true, the player respawns at his spawn location using the following code.

x = xstart;
y = ystart;

After that create a piece of code which destroys he player when he is touched by the enemy. Then Do everything you've done for player1 for player2 as well.

Take a look at how I did it (including assignment answers) here.

Post 4 - Enemy Behaviour

Next up we'll begin working on our enemy. To start off we will make him patrol between walls, meaning we want to our enemy to do the following:

  • Walk until there is collision with a tile in front of him
  • Short pause 
  • Turn around
  • Walk in opposite direction until there is collision with a tile in front of him
  • etc
MOVEMENT
First let's define our enemie's direction. Add a Create Event to the enemy object and write the following.

enemy_direction = 1;

We have now created enemy_direction and have given it the value 1. Now lets use it to make our enemy walk. Add a Step Event to the enemy object and use the enemy_direction as it's walking speed.

x += enemy_direction;

PATROLLING BEHAVIOUR
Next let's make the enemy stop, wait and turn around. For the wait we need a timer. We can create one in the Create Event.

wait_counter = 0;

We have now created wait_counter and set it to 0. We continue on the patrolling code by typing the following in the enemy's Step Event.

if enemy_direction = 1
{
    if !(place_free(x+1,y))
    {
        wait_counter += 1;
        x = xprevious;
        
        if wait_counter >= 30
        {
            enemy_direction = -1;
            wait_counter = 0;
        }        
    }
}

That's quite a bit of code in one go, and we're not even done yet. Let's go through what we just coded. First we check if the enemy_direction is 1 (to the right). As we have created our enemy_direction with value 1 in the Create Event, in the beginning this will always be true.

Next we check if there isn't any place free right in front of the enemy. If this is true (meaning there is a solid object in front of him) we add 1 to the wait_counter every frame and the enemies x position is changed to his last known x position. This means he has stopped moving.

Afterwards we check if the wait_counter has reached 30. If so, the enemy_direction changes to -1 and the wait_counter is reset to 0. (I run my game on 60 frames per second, meaning 30 frames = 0.5 seconds. You can change your framerate under the Settings tab in your Room)

So to recap: The enemy walks to the right, stops when he encounters a solid object in front of him, waits for 0.5 seconds and turns around. But we aren't finished yet. We haven't told the enemy what to do once he's turned around. Luckily it's not that hard anymore as we want him to do the exact same thing but in the opposite direction. So straight underneath the above code we write the following.

else
{
    if !(place_free(x-1,y))
    {
        wait_counter +=1;
        x = xprevious ;
        
        if wait_counter >= 30
        {
            enemy_direction = 1;
            wait_counter = 0;
        }
    }
}

This does the exact same as the previous piece of code except it checks whenever the direction is not 1 (else) and changes the direction to 1 after the counter has reached 0.5 seconds.

We now have patrolling enemies!

ASSIGNMENT: CHECK FOR GAPS, FASTER MOVEMENT, INCREASED WAIT TIME
Make sure that whenever the enemy encounters a gap in the ground, he also stops moving, waits and turns around. Also increase his movement speed by 3(without changing enemy_direction in the Create Event) and his wait time to 1.0 seconds.

Take a look at how I did it (including assignment answers) here.

Thursday 2 August 2012

Post 3 - Sprite Index

In post 2 we gave our players basic movement options, going left, right and jumping. This post we'll add ducking to this list. I'm putting ducking in a separate post because making the players duck is a tad different compared to the other basic movements. Mind you, its quite easy.

SPRITE INDEX
When player1 ducks, we want him to be half the size of his original sprite. To do this we create a new sprite exactly the way we created the other sprites (See Post 1) except this time, when we are in the image editor, we make sure that we fill only the bottom half of the sprite (the sprite is 16x32, fill the bottom 16x16). Be sure you use the same color as before.

Now you have a second sprite which is half the size of the original sprite. Give the sprite a easy to remember name in line with the naming convention you used for the other sprites. My original sprite is called spr_char. My ducking sprite is called spr_char_low.

What we want is that player1 switches to the new sprite whenever he ducks. We do this with sprite_index. But first we'll use the following code learned in our previous post, assigning a key and checking if player1 is standing on a tile. Choose whichever key you want to use. I'll use the down arrow. We follow this with sprite_index which we assign to our newly made sprite. We do this in our player1's Step Event, in the same place where we wrote our previous movement code.

if keyboard_check(vk_down) && !(place_free(x,y+1))
{
    sprite_index = spr_char_low;
}
else
{
   sprite_index = spr_char;
}

Now you can duck and the place_free check ensures we can only duck when standing on a tile (not while jumping/falling etc). If we try this code out we see that we can still move around while ducking. To fix this we edit our movement code.

if (keyboard_check(vk_right) && place_free(x+walk_speed,y)) && sprite_index = spr_char
{
    x += walk_speed;
} 
 

Now we have included a check in the movement code which checks if the sprite of the player is the normal sprite meaning he can't move around if he's ducking because then he uses another sprite.

ASSIGNMENT: MAKE PLAYER2 DUCK
Do the same you did for player1 to player2 to get a hang of it. Also build in the sprite check for movement to the left and jumping.

Take a look at how I did it (including assignment answers) here.

Sunday 1 July 2012

Post 2 - Basic Movement & Collision

Last post we made player1, player 2 and tile objects. Now we will give them basic movement and collision. We will do this with code.

PLAYER COLLISION WITH TILES
First let's make sure the players don't fall through the tiles. Go to player 1's Object Properties and click the Add Event button near the bottom, then click Step and at the drop down menu click Step again. You have now added an empty step event. Whatever you put in a step event Game Maker will check every single frame.

Select the Step you just created and on the right side of the Object Properties window click the Control tab. Click and drag the Execute Code button from under the Code section into the empty area to the left of it. It is in this file we will write the code for player collision with the tiles and the player's basic movement.

Let's start with a simple if-else statement which defines the player's gravity.

if (place_free(x,y+1))
{
    gravity = .2;
}
else
{
    gravity = 0;
}

With this code we check if there is any free space (meaning there is no solid object, in our case a tile) at position x, y+1 from player1. The x coordinates we check are the same as the players x coordinates but we check one pixel below the players y coordinates, which is obvious because if a player would be standing on a tile it would be right below the player. Basically what we check here is if there is a tile right below the player or not.

If there is no tile (so there is place free), the player's gravity is set to 0.2. Else (meaning there is a tile/no place is free) gravity is set to 0. This means player1 doesn't fall.

Next add a Collision Event to the player1 object, then choose the tile object as the object with which it collides. Again drag the Execute Code button from the Control tab into the empty space an write the following code in it. This piece of code ensures you don't fall through the tiles.

move_contact_solid(270, vspeed)
gravity = 0;
vspeed = 0;

BASIC PLAYER CONTROLS

Now we're going to make sure we can move player1 with key presses. To do this we must first set the player's walking speed and jumping speed.

At player1's Object Properties click Add Event, then click Create. A Create Event is checked at the beginning of each Room, instead of every frame, like the Step Event. Now drag the Execute Code button into the empty area, just like you did before. In this piece of code we are going to define the variables for walking speed and jumping speed so we can refer to them later in different pieces of code. To do this write the following.

walk_speed = 3;
jump_speed = 3;


We have just created walk_speed and decided it's worth is 3, same goes for jump_speed.

Now go to the step event. We are going to make the player walk to the right.

if (keyboard_check(vk_right) && place_free(x+walk_speed,y))
{
    x += walk_speed;
} 


So basically what we do here is check if the right arrow key is pressed (keyboard_check) and if there is place free in the direction player1 is going to move (place_free). To check if theres place free we add the walk_speed to the player's x position, as the walk speed is how many pixels the player will be moving per frame. So if the right arrow key is pressed and there is space to move, we add walk_speed (which we defined in our Create Event as 3) to the player's x position every frame.

If you want to use a letter key instead of arrows or other special keys (shift, spacebar, ctrl etc), for example D, use the following piece of code isntead.

if (keyboard_check(ord('D')) && place_free(x+walk_speed,y))
{
    x += walk_speed;
} 


ASSIGNMENT: FINISH PLAYER MOVEMENT (LEFT, JUMPING)
Make sure player1 is able to move to the left with a key press and is able to jump with a key press. Use the jump_speed we defined in the Create Event for this and use keyboard_check_pressed instead of keyboard_check. This will make sure the player doesn't keep jumping when keeping the key pressed. Afterwards give player2 the same movement possibilities using other keys on the keyboard.

Tip: Use the following piece of code in the player's Step Event. Try to figure out what this code does.

if ((vspeed < 0) && !place_free(x,y+vspeed))
{
    vspeed = 0;
}

Take a look at how I did it (including assignment answers) here.

Sunday 24 June 2012

Post 1 - Object creation

I will illustrate this first section of the post step by step for you to get a basic understanding of where to click, where that leads, what this button does etc. After this section my explanations will be less illustrated.

Let's start off by creating a tile. Tiles are blocks of which your level exists.

CREATING A SPRITE
If you open Game Maker you will be presented with a list of folders on the left side of the screen. The top folder is the Sprites folder. Right click this folder and select Create Sprite.


You are now presented with the Sprite Properties screen. First lets give the sprite an appropriate name. In the top left of the Sprite Properties screen you can change the name of your sprite. I call mine 'spr_tile'. All my sprite names will start with 'spr' for the sake of consistency and easy reference. 

Next we'll draw the sprite. We do this by clicking Edit Sprite. This opens the Sprite Editor. Once in the sprite editor click the empty page icon Create A New Sprite




You will be prompted to fill in the height and the width of the new sprite. As we are making a tile it is generally good to keep to a square. In my case my tile will be 16 by 16, but any size will suffice, as long as width and height are the same. When you click OK Image 0 will be added to the Sprite Editor. Double click Image 0 to start drawing your sprite in the Image Editor.



When the Image Editor is opens it might look like there is nothing to edit. Just scroll your mouse wheel forward and you will see the editable sprite enlarge. Once it is large enough for your taste, grab the Fill An Area tool (looks like a paint bucket) and give your tile a color by clicking on the empty sprite with it. Afterwards click the green check button in the upper left corner of the Image Editor to accept your changes. Click the green check button in the upper left corner of the Sprite Editor as well. 


CREATING AN OBJECT
So now you have a sprite. To be able to use this sprite as an object in the game we must first create an object and assign the sprite to it. To do this right click on the Objects folder in the list of folders at the left of the screen. Select Create Object. This will open Object Properties. We will make this object our tile object, so lets give it an appropriate name again. I've called mine 'obj_tile'. Just like how I start all my sprites names with 'spr' I'll start all my object names with 'obj'.

Now you must assign the correct sprite to this object by clicking on the box that says <no sprite> and selecting 'spr_tile'. Afterwards check the Solid box and click OK. You have now created a tile object. Next let's build a level out of this tile.

CREATING A ROOM
In the list of folders on the left side of the screen, right click on Rooms and select Create Room. This will open the Room Properties window, Game Maker's level editor. In the left column you'll see the following tabs: Objects, Settings, Tiles, Backgrounds and Views. In the settings tab you can change the name and size of the room if you desire.

Click the Objects tab and click on the empty space below it and select 'obj_tile'. With this object selected you can now build a little level by clicking on the grid on the right. Keeping shift down while clicking will allow you to easily draw with the selected object.

ASSIGNMENT: CREATE TWO CHARACTER SPRITES
Now create 3 new objects, one for player 1, one for player 2 and one for the enemy, following the steps above. The width of these sprites should be the same as that of the tile, the height should be twice as much. So in my case that would be 16x32. Don't forget about name consistency. Also: the objects must not be solid. When the objects are created, place them in the room you have created.

Take a look at how I did it (including assignment answers) here.

Introduction

Hello and welcome,

Over the next few weeks I'll be trying to duplicate the main mechanics of my final exam project (designed but not programmed by me) in Game Maker. I do this in an effort to teach myself simple programming and get acquainted with the many features of Game Maker.

On this blog you can follow my efforts and findings. If you as new to programming or Game Maker as I am, you will be able to learn along with me by following my steps.

The game I will be reproducing is a two-player offline co-op 2D sneaking game played with Xbox360 controllers.

When we are done we ill have:
  • 2 players with movement, jumping and ducking.
  • A tile with which we can create levels.
  • Patrolling enemies with sightcones which kill on collision.
  • A hiding mechanic for the players.
  • Collectibles and scores.
Good luck!