How to make an Animated/Multi-Sprite Platformer

This tutorial will teach you how to make an animated platformer. This tutorial was written using Game Maker 7.

This tutorial was made by spacechase0spacechase0.

There may be an easier way to do this, but this is how I do it.

Note to the reader

This tutorial assumes that you have the following objects/sprites with certain names:

Player Object obj_player
Player Idle Right Sprite spr_player_idle_right
Player Idle Left Sprite spr_player_idle_left
Player Walking Right Sprite spr_player_walk_right
Player Walking Left Sprite spr_player_walk_left
Player Jump Right Sprite spr_player_jump_right
Player Jump Left Sprite spr_player_jump_left
Player Fall Right Sprite spr_player_fall_right
Player Fall Left Sprite spr_player_fall_left
Player Crouch Right Sprite spr_player_crouch_right
Player Crouch Left Sprite spr_player_crouch_left
Player Ladder Sprite spr_player_ladder
Player Mask Sprite spr_player_mask
Player Crouch Mask Sprite spr_player_crouch_mask
Block Object obj_block
Block Sprite spr_block
Ladder Object obj_ladder
Ladder Sprite spr_ladder
Draw Object obj_draw
Coin Object obj_coin
Coin Sprite spr_coin
Enemy Object obj_enemy
Enemy Right Sprite spr_enemy_right
Enemy Left Sprite spr_enemy_left

Player Object

Create Event

In the Create Event of the player, set the following variables:

face = 2
jump = 1
move = 1
fall = 1
crouch = 1
ladder = 1

If you don't want some of the variables, then take them out. Just be sure to take out bits of code later that might use those variables. If you don't you will get an error. Examples on how to remove some of the variables will be listed later.

This code will put the facing variable (which direction you are facing, 1 = left 2 = right), jumping variable (going up, 1 = no 2 = yes), moving variable (whether you are moving or not, 1 = no 2 = yes), falling variable (going down, 1 = no 2 = yes), crouching variable (crouching check, 1 = no 2 = yes), and ladder variable (on a ladder check, 1 = no 2 = yes). You can use false for 1 and true for 2, but make sure that if you change a variable you have to remember to make it check true/false and not 1 and 2.

Please note that these are just interpretations of it, 1 doesn't really mean no or left and 2 doesn't really mean yes or right.

Step Event

This section contains the code you will need to put in the Step Event.

Gravity

Gravity can be pretty easy to make, especially if you know what you are doing. In the Step Event of the player, put the following code:

if place_free(x,y+1) and distance_to_object(obj_ladder) >= 1 
{
     gravity = 0.45 
     ladder = 1
}
if !place_free(x,y+1) and distance_to_object(obj_ladder) >= 1 
{
     gravity = 0 
     jump = 1 
     fall = 1 
     ladder = 1
}
if distance_to_object(obj_ladder) <= 0 
{
     gravity = 0 
     jump = 1 
     fall = 1 
     ladder = 2 
     vspeed = 0
}
gravity_direction = 270
if vspeed > 9.5 
     {vspeed = 9.5}
if vspeed > 0 
     {fall = 2 jump = 1}
if vspeed < 0 
     {fall = 1 jump = 2}
if vspeed = 0 
     {fall = 1 jump = 1}

Now, lets take a look at the code and disect it. If you are learning GML, this might help you.


if place_free(x,y+1) and distance_to_object(obj_ladder) >= 1 
{
     gravity = 0.45 
     ladder = 1
}

This code checks if the player is in the air (place_free(x,y+1)) and if you are not at the ladder object (distance_to_object(obj_ladder) >= 1). Then, in brackets, it tells the program what to do if you are in the air. It tells the player to have gravity almost half of one (gravity = 0.45) and it sets the ladder variable to 1, meaning you are not on a ladder.
if !place_free(x,y+1) and distance_to_object(obj_ladder) >= 1 
{
     gravity = 0 
     jump = 1 
     fall = 1 
     ladder = 1
}

This line of code is almost exactly like the previous, but they are both important. This line checks if you are not on the ground (the ! is not). Also, it checks if you are not on a ladder, as before. If both are true, then several things will happen. First, it will turn the gravity off. It will also change the jumping and falling variables to 1, which means you are not jumping or falling. It also set the ladder variable to 2, for purposes seen later.
if distance_to_object(obj_ladder) <= 0 
{
     gravity = 0 
     jump = 1 
     fall = 1 
     ladder = 2 
     vspeed = 0
}

This line of code is a little different from the other two. This one checks if you are on the ladder, and then it turns the gravity off, sets the jump/fall variables to 1, sets the vspeed to 0 (incase you fell onto or jumped onto the ladder), and sets the ladder variable to 2. This will be used later in the step event.
gravity_direction = 270

This makees sure the every step the gravity is going down. Remember, if you are changing the gravity direction, 0 degrees is right, and it goes counter-clockwise up to 360.
if vspeed > 10 
     {vspeed = 10}

This makes sure that the vspeed does not go higher than 10. This is so that gravity does not pull too hard on the player. Players can go through objects if the gravity is high enough.
if vspeed > 0 
     {fall = 2 jump = 1}

This sets the jump/fall variables, used for later.
if vspeed < 0 
     {fall = 1 jump = 2}

This sets the jump/fall variables, used for later.
if vspeed = 0 
     {fall = 1 jump = 1}

This sets the jump/fall variables, used for later.

Movement, Sprites, Etc.

Time for more code! This section will also explain each line.

if keyboard_check(vk_left) and place_free(x-5,y) 
{
     x-=5 
     move = 2 
     face = 1
}
if keyboard_check(vk_right) and place_free(x+5,y) 
{
     x+=5 
     move = 2 
face = 2
}
if keyboard_check_pressed(vk_up) and !place_free(x,y+1) and ladder = 1
     {vspeed = -9}
if keyboard_check(vk_up) and ladder = 2 
{
     y -= 3 
     image_speed = 0.33
}
if keyboard_check(vk_down) and move = 1 and ladder = 1
{
     crouch = 2}
if keyboard_check(vk_down) and ladder = 2 
{
     y += 3 
     image_speed = 0.33
}
if !keyboard_check(vk_down) and !keyboard_check(vk_up) and ladder = 2 
     {image_speed = 0}
if !keyboard_check(vk_left) and !keyboard_check(vk_right) 
     {move = 1}
if keyboard_check(vk_left) and keyboard_check(vk_right) 
     {move = 1}
if !keyboard_check(vk_down) 
     {crouch = 1}

You can use this for all of the controls. If you don't understand this, then you should keep reading.


if keyboard_check(vk_left) and place_free(x-5,y) 
{
     x-=5 
     move = 2 
     face = 1
}

This code is very different then the one in the gravity section. It checks if you are holding left (keyboard_check(vk_left)) and if the place 5 pixels to the left is empty. If it is, then it moves the player to the plae 5 pixels to the left, sets the moving variable at 2, and the face variable to 1.
if keyboard_check(vk_right) and place_free(x+5,y) 
{
     x+=5 
     move = 2 
     face = 2
}

This is almost the same as the last line, but it is not. It checks if your are pressing right instead of left, and checks/moves you to 5 pixels to the right instead of 5 pixels to the left. Another difference is that it sets face at 2 instead of 1. The only thing that is the same is that it sets move at 2.
if keyboard_check_pressed(vk_up) and !place_free(x,y+1) and ladder = 1 {vspeed = -9}

Jumping is fairly simple on platformers. This check if you have pressed up, and when you do, if you are on solid ground and not on a ladder. Then it sets the vspeed to -9, which is up. This pretty much makes you go up against gravity. The gravity will slowly make the vspeed higher (higher because jumping sets it to a negative).
if keyboard_check(vk_down) and move = 1 and ladder = 1 
     {crouch = 2}

This checks if you are holding down and if you are not moving and not on a ladder. If so, it sets the crouching variable, which is used later on.
if keyboard_check(vk_down) and ladder = 2 
{
     y += 3 
     image_speed = 1
}

Another bit of code, another explanation. What this does is if you are holding the down arrow key and you are on a ladder then it makes you move down a little bit on the ladder. Don't worry, all of the sprite and mask handling will be done at the end of the step event. The image_speed is for if the arms/legs/etc. are moving as if you are actually climbing. See explanation for the code below for more info.
if !keyboard_check(vk_down) and !keyboard_check(vk_up) and ladder = 2 
     {image_speed = 0}

This bit of code is very important, unless you have ladder climbing sprite that doesn't have moving body parts. Pretty much it makes it where the character doesn't move when you aren't going up and down, useful if the arms and legs move up and down as if you were really climbing.
if !keyboard_check(vk_left) and !keyboard_check(vk_right) 
     {move = 1}

This is used for when you stop moving, it sets move to 1 so that sprite handling will be accurate for later on in the Step Event.
if keyboard_check(vk_left) and keyboard_check(vk_right) 
     {move = 1}

This is a debug for the moving. This makes it where you don't have a walking animation when you are holding left and then also start holding right or vice versa.
if !keyboard_check(vk_down) 
     {crouch = 1}

If you are not holding the down arrow key, it sets crouch to 1.

Sprite and Mask Handling

Time to start using those variables! Here is the code for this section:

if move = 1 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_idle_left 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if move = 1 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_idle_right 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if move = 2 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_walk_left 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if move = 2 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_walk_right 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if jump = 2 and fall = 1 and face = 1 and ladder = 1 
{
     sprite_index = spr_player_jump_left 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if jump = 2 and fall = 1 and face = 2 and ladder = 1 
{
     sprite_index = spr_player_jump_right 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if fall = 2 and jump = 1 and face = 1 and ladder = 1 
{
     sprite_index = spr_player_fall_left 
     image_speed = 1 
     mask_index = spr_player_mask
} 
if fall = 2 and jump = 1 and face = 2 and ladder = 1 
{
     sprite_index = spr_player_fall_right 
     image_speed = 1 
     mask_index = spr_player_mask
}
if crouch = 2 and move = 1 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_crouch_left 
     image_speed = 1 
     mask_index = spr_player_crouch_mask
} 
if crouch = 2 and move = 1 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_crouch_right 
     image_speed = 1 
     mask_index = spr_player_crouch_mask
} 
if ladder = 2 
     {sprite_index = spr_player_ladder}

Explanations anyone? Here is one for each line. All of the image_speed settings are used for debug purposes, and the mask stuff is for masking sure the collision checking is right.


if move = 1 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_idle_left 
     image_speed = 1
}

If you are not moving, facing left, not jumping and, not falling, and not on a ladder then it will set the sprite to the spr_player_idle_left.
if move = 1 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_idle_right 
     image_speed = 1
}

This is the same as the previous bit, except it is when you stopped facing right it sets it to spr_player_idle_right.
if move = 2 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_walk_left 
     image_speed = 1
}

If you are walking to the left on the ground and not on a ladder, then this will put the walking left animation.
if move = 2 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_walk_right 
     image_speed = 1
}

Walking right will trigger this code. It puts the animation to the correct sprite.
if jump = 2 and fall = 1 and face = 1 and ladder = 1 
{
     sprite_index = spr_player_jump_left 
     image_speed = 1
}

When you jump and are facing left, then the player will get this sprite.
if jump = 2 and fall = 1 and face = 2 and ladder = 1 
{
     sprite_index = spr_player_jump_right 
     image_speed = 1
}

Jumping right will make you get the sprite spr_player_jump_right.
if fall = 2 and jump = 1 and face = 1 and ladder = 1 
{
     sprite_index = spr_player_fall_left 
     image_speed = 1
}

Did you just jump off a cloud on the left side? Well this piece of code will put the proper animation.
if fall = 2 and jump = 1 and face = 2 and ladder = 1 
{
     sprite_index = spr_player_fall_right 
     image_speed = 1
}

When you play the first level of Mario, there is usually a bunch of stairs to jump onto to get to the top of the flag. What happens when you miss the flag? You go into the spr_player_fall_right sprite.
if crouch = 2 and move = 1 and face = 1 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_crouch_left 
     image_speed = 1
}

What happens if something is flying towards you? You need to crouch! If you are were going left when you crouched, then this bit of code is sure to save you!
if crouch = 2 and move = 1 and face = 2 and jump = 1 and fall = 1 and ladder = 1 
{
     sprite_index = spr_player_crouch_right 
     image_speed = 1
}

Did you accidently poke a beehive on a platformer? If this code is in your step event and you are running to the right, then you can crouch correctly.
if ladder = 2 
     {sprite_index = spr_player_ladder}

This will make the player's sprite change into spr_player_ladder.

Other changes to obj_player

Do NOT make the player solid because it might mess up the ladder. In the collision event with obj_block, put

if vspeed > 0 and !place_free(x,y+vspeed) 
     {move_contact(270)}
vspeed = 0

This code is very important! It keeps you from falling through the block.

Be sure to give the player one of the idle sprites before you start the game or else the player will be invisible. Also, give the player a mask of the sprite spr_player_mask.

Changes to other objects

Give obj_block the spr_block as a sprite. Make it solid
Also, make obj_ladder non-solid, and give it spr_ladder as a sprite.

Collectables

Create a sprite name spr_coin and an object called obj_coin with spr_coin as a sprite. Be sure it is not solid. Also, make an object called obj_draw and make it persistent. Be sure it is not solid and do not give it a sprite. All of the code needed to put in the player's collision object with the collectable is:

global.points += 1
with (other) 
     {instance_destroy()}

Put this in the create event of obj_draw:
global.points = 0

And put this in the Draw event of obj_draw
draw_text(8,8,global.points)

Keep reading for an explanation of the code.
global.points += 1

This adds one point to the variable when the player grabs the coin.
with (other) 
     {instance_destroy()}

Whenever other is in a collision event, it means the instance of the object you just touched. Using other instead of obj_coin will make sure that only the coin you just grabbed gets deleted. The with means that whatever is in the brackets (in this case instance_destroy()) will happen to the object in the parenthesis.
global.points = 0

This is in the game start event of obj_draw. This will make it where you can use global.points.
draw_text(8,8,'Points: '+string(global.points))

This line of code will draw how many points you have near the top leaft corner of the course.

Now just place obj_draw in the first room and place the obj_coin where you want it.

Enemies

Now you will be able to make a simple enemy that goes left and right.

dir = choose(2,-2)

This goes in the create event. Basically, this will just pick a direction to go when the enemy is created.
if place_free(x,y+1)
{
     gravity = 0.45 

}
else
{
    gravity = 0
}
gravity_direction = 270
if vspeed > 9.5 
     {vspeed = 9.5}

if place_free(x+dir,y)
{
    x += dir
}
else
{
    dir = -dir
}

if place_meeting(x+dir,y,obj_player) or place_meeting(x-dir,y,obj_player) and !(place_meeting(x,y+1,obj_player))
{
    with (obj_player)
    {
        instance_destroy();
    }
}
else if place_meeting(x,y+1,obj_player)
{
    with (obj_player)
    {
        vspeed = -4
    }
    instance_destroy()
}

if dir > 0
{
    sprite_index = spr_enemy_right
}
else
{
    sprite_index = spr_enemy_left
}

Put this in the step event. The beginning part is an edited version of the gravity code earlier, so we won't talk about it.
if place_free(x+dir,y)
{
    x += dir
}
else
{
    dir = -dir
}

This just makes the enemy go in the current direction if the place is free, and otherwise he turns around.
if place_meeting(x+dir,y,obj_player) or place_meeting(x-dir,y,obj_player) and !(place_meeting(x,y+1,obj_player))
{
    with (obj_player)
    {
        instance_destroy();
    }
}
else if place_meeting(x,y+1,obj_player)
{
    with (obj_player)
    {
        vspeed = -4
    }
    instance_destroy()
}

This fancy part of the script is necessary. If you run into the side of the enemy, but are not on top of him, he will destroy you. But if you jump on him, he will die.
if dir > 0
{
    sprite_index = spr_enemy_right
}
else
{
    sprite_index = spr_enemy_left
}

This last part is nothing fancy, it just makes the enemy show the right direction.

Coming soon

  1. Enemies (like a goomba)
  2. Temporary invincibility (like a star)
  3. Trail effect
  4. Slope movement
  5. Lava/Killing Blocks
  6. Kirby-Style Jumping
  7. Example!

Post suggestions here.

Backlinks

These pages link back to this page.

Side Notes

Please note that this is the last thing I will do with game maker. I have moved on to C++, and I will try to finish this, but other than that I probably won't be here very much.