SoulHow to Make a Platform Game (Game Maker)

Skill Level: Intermediate user (5)

This is the first of the SoulHow Game Maker assistance guides. I’m going to discuss how to make a snazzy platform game engine. We will be using Game Maker Version 7.0, but it…might…work in earlier versions. I don’t know because I don’t feel like checking. If you don’t have the program at all, get it here.

You can build on other features to this example after you enter the basic code given in the guide.   In addition, if you feel like doing something another way, go ahead, because this guide is as much an idea spawner as it is an example. By the way, you’ll need to understand how to use GML. If you don’t, it’s not that hard, so bring up the GM manual and get cracking. In addition, this guide assumes you understand how to do things like creating and drawing sprites, making objects, and other GM basics. You’ll know if you understand them or not; if you don’t, again, just read the GM manual.

Ok, moving right along, let’s open Game Maker and click the “New Game” icon. It’s the little blank page, you know, the same one in every program out there.

Now we have complete blankness, so first we need some sprites. Create three sprites, and draw a character in each one in a different pose. First, standing (named sprPlayerStand), then walking (sprPlayerWalk), then in the air (sprPlayerInAir). I’m going to assume the only animated sprite is the walking one. Make sure all the sprites have precise collision checking off, so it uses a rectangle to check for collisions instead of the sprite, and also make sure their origins are centered (click the “center” button). NOTE: This assumes your player sprites are centered in the middle of the frame. If not, you’re going to have to set the origin to midway between the bounding box values. For example, if the left value is 10 and the right value is 25, set the x origin to midway between those which is 18. Do something similar with the y origin using the top and bottom bounding box values.

The last sprite we need is a temporary block sprite, so make a 16×16 sprite and fill it with black. Turn off transparent so we can see the black color, and close out.

Finally, we get to make some objects! Create two objects and call them objPlayer and objBlock. DON’T make objBlock solid, contrary to what most people would tell you. I have another article on this blog explaining why. Yes, our block sprite looks ugly right now, but that can be fixed by simply turning the blocks invisible and making a tileset to put over the blocks (not covered in this guide, but shouldn’t be too difficult for you to figure out if you don’t already know how)

Now close out of the block object, as we don’t need to do anything with it (the poor thing doesn’t even get any code).

objPlayer needs two pieces of code, though. Let’s start at the create event. We want some variables that tell our player things like how fast to run and how high to jump, along with which way for the object to move. Here’s what I did:

//Set up some variables for certain speeds
walksp=4; //Walking speed (4 pixels per frame)
jumpsp=-14; //Jumping speed (negative because it goes up)
grav=1; //Gravity strength (usually a small value)
//These variables are actually used to move the player
hsp=0; //Horizontal speed
vsp=0; //Vertical speed
ground=1; //Whether the player is on the ground

Next, we move to the step event. We want to use the step event to do lots of things, including moving the player and checking for colliding with the wall. I’ll use comments to explain the code. I finally got the indentations to work, and in addition I’ve color-coded it to make it easier to read and understand.


//Keyboard constants
//We use these so we can just type the variables
//instead of "keyboard_check(*)"

KEY_RIGHT=keyboard_check(vk_right);
KEY_LEFT=keyboard_check(vk_left);
KEY_JUMP=keyboard_check_pressed(vk_up); 
//This one's for variable jump height:
KEY_FALL=keyboard_check_released(vk_up);
//Now check if the player pressed left or right and move
if (KEY_RIGHT)
{
   hsp=walksp; //Walk right
   image_xscale=1; //Face right
}
if (KEY_LEFT)
{
   hsp=-walksp; //Walk left
   image_xscale=-1; //Face left
}
//Stop moving when no keys are pressed
if (!KEY_RIGHT and !KEY_LEFT) hsp=0;
//Make sure we don't hit a wall
if (place_meeting(x+hsp,y,objBlock))
{
   //Move until contact with the wall
   if (hsp!=0)
      while (!place_meeting(x+sign(hsp),y,objBlock))
         x+=sign(hsp);
   hsp=0;
}
//Because we don't use hspeed, we got to move ourselves
x+=hsp;
//Now for vertical motion (jumping and falling)
//Is the player in the air?
if (place_meeting(x,y+1,objBlock)) grounded=1;
else grounded=0;
//Jump with the up key when on the ground
if (KEY_JUMP and grounded)
{
   vsp=jumpsp;
}
//If we're in air moving up and jump key is released, we remove
//upward motion (so we fall and get variable jump height)
if (KEY_FALL and !grounded and vsp<-1) vsp=-1;
//Fall with gravity
if (!grounded) vsp+=grav;
//Now it's more complicated.
//When hitting the ceiling, vertical speed must stop.
//The if statement says, "if we hit the ceiling and are moving up" 
if (place_meeting(x,y+vsp,objBlock) && vsp<0)
{
   //We must move up until contact with the ceiling
   while (!place_meeting(x,y+sign(vsp),objBlock)) y+=sign(vsp);
   vsp=0;
}
//But if we are moving down and hit the floor, we have to land
if (place_meeting(x,y+vsp,objBlock) and vsp>0)
{
   //Move so we hit the ground
   var cc;
   cc=vsp+1; //A counter, so we don't get an infinite loop
   //Move down until we hit the floor
   while (!place_meeting(x,y+1,objBlock) and cc>=0) y+=1;
   //Now ground the player
   grounded=1;
   vsp=0;
}
//Again, we're not using vspeed, so we have to move ourselves
y+=vsp;
//Animation - check what our sprite's state is and set accordingly
if (grounded) //If we're grounded
{
   if (hsp==0) //Then if we're not moving, change to stand sprite
   {
      sprite_index=sprPlayerStand;
      image_speed=0; //Don't animate
   }
   else //But if we are moving, change to walk sprite
   {
      //Reset image index if just now switching to walk sprite
      if (sprite_index!=sprPlayerWalk) image_index=0;
      sprite_index=sprPlayerWalk;
      image_speed=0.5; //Change this to whatever works for you
   }
}
else //If we're not grounded, change to in air sprite
{
   sprite_index=sprPlayerInAir;
   image_speed=0; //Don't animate
}

The funny thing about this code is that the player never actually touches a wall. This generally makes for smoother gameplay. Note also that the reason the sprites are centered is because we use the image_xscale variable to control which direction the player is facing.

Well that’s all for now. Try out your newly created engine, and see how it runs. Put blocks wherever you want, and have the character jump on them. Copy this guide for now, but I encourage you to scan it and figure out just how it works so you can build on to it and change it to suit your preferences. Remember, the most important thing when using any sort of tutorial is to always make sure you understand why some bits of code work, instead of just knowing that they work.

All comments and ideas for improvement welcome.  If you enjoyed this article, please consider checking out the rest of the blog.

If you have a technical question, such as “How do I do this” or “this is not working right” (relative to something with your Game Maker game after reading this tutorial), please head over to the Game Maker Community and ask there.  I can’t answer any such questions in this blog and the members at the GMC will be more than capable to help you.  Unfortunately any technical-question-related comments will be deleted without a response.  Any other comments, however, will be welcomed wholeheartedly.  Thanks!

31 Responses

  1. could u plz make this so u can make platform games with ver5.3.

  2. Unfortunately, I’m not familiar any more with the large amount of differences between GM5.x and 7.0, so I can’t really help you there. I think the only problems will be with image_xscale (as it for some reason seems to function incorrectly in GM5.x) and keyboard_check_pressed() (it doesn’t exist in GM5.x; you’ll have to look for an alternative).

  3. Thanks alot, I hope this helps with my Samus game ^^. I make her jump and when she comes down she sticks to the floor…. anyway Ill bet this fixs the problem.

    Thanks again.

  4. btw good article

  5. Thanks man, gave me a kick start!

  6. Nice tutorial. It helped me with some landing trouble I was having. However, it’s not perfect, and I’d like to point out a way it could be improved.

    To prevent the problem with the player not hitting the ceiling before coming down (i.e. stopping and falling before actually getting near the ceiling.), here’s what you do.

    1. Delete the line of code underneath “// When hitting the ceiling…”. That’s what’s causing the problem.

    2. Instead of having y += vsp, have the following

    if (vsp > 0) // Check if vsp’s positive.
    {
    repeat (vsp)
    {
    if (place_meeting(x,y+1,objBlock) == false)
    then y += 1; // Instead of jumping to the end position, the object actually moves through every pixel in between it and where it’s going.
    }
    }
    else // If vsp’s negative
    {
    repeat (-vsp)
    {
    if (place_meeting(x,y-1,objBlock) == false)
    then y -= 1; // This is what actually fixes the problem, I’m sure you can see why.
    }
    }

    So yeah, there you have it. It may be a little long-winded, and could probably be optimized, but I personally find that this is a great way to fix the problem of the character not actually hitting the ceiling before coming down.

    Oh, and you’ll want to do something similar for hsp, so that the character actually hits the wall before stopping. Just replace the ‘vsp’s with ‘hsp’s, the ‘x,y+/-1’s with ‘x+/-1,y’s and the ‘y +/-= 1’s with ‘x +/-= 1’s

  7. Thanks for the comment/improvement. I didn’t exactly use your code, but I did use your idea, so I put your name in the update.

  8. Ah, your way is much more elegant. Glad to be of assistance. ^_^

  9. Er, you should’ve put a collision check between the floor/wall and player. If you don’t understand, check these out:
    http://www.youtube.com/watch?v=7qNLiBEHsVw
    http://www.youtube.com/watch?v=5E_fJ9A6csU&feature=related

    These videos continue each other, so check BOTH out.

  10. I don’t like to disagree with suggestions in comments, but I’m going to have to disagree with this one. Referring to the tutorials in your links, I actually wrote a whole article on why to never use the “solid” option in your games (here), you might want to check it out.

    But I’m curious; what, exactly, is your reasoning? The gameplay will run much smoother when the player never actually touches the wall, at all; there’s no need for an actual collision event. The code just checks whether the player would collide in the next frame.

    If you don’t believe me, try this method out yourself. He never touches a wall so he’ll never have a chance to get stuck or caught.

    In addition, you can add custom code to the engine which will easily check if the player would have hit a wall (and to do something if he has, whatever you need him to do), without him actually having to touch it.

    Hope this helped. ^_^

  11. Badass.

  12. very helpful!

  13. This is great and really helped as I’m just starting to learn some basic GML.

  14. Thanks, man, this should help me fix all of the collision problems I was having creating a good sword fighting platformer! BTW I would like to know how you can jump through something from the bottom and land on it. I may figure this out myself, but still…

  15. I never liked the radical mirror/pivot that image_xscale() produces, so I do the following to make the sprite mirror in place…

    replace –

    if (KEY_RIGHT)
    {
    hsp=walksp; //Walk right
    image_xscale=1; //Face right
    }

    with -

    if (KEY_RIGHT)
    {
    hsp=walksp; //Walk right

    if (image_xscale=-1)
    {
    hsp-=sprite_width; // xscale compensation
    image_xscale=1; //Face right
    }
    }

  16. Hi yguy,

    Just for clarification, using only image_xscale=-1 won’t produce a pivot if you center your sprite origins. I think you might have missed that line in the tutorial. It’s in paragraph 4:

    “…and also make sure their origins are centered (click the “center” button).”

    If, however, you for one reason or another do not want to center the origin, then yes, you can use code similar to what you wrote.

    Thanks for your comment!

  17. You have a LOT in the step event. Any way that can be…erm…reduced?
    Just a thought
    ♥Constromlie

  18. Hey James/Constromlie,

    You’re right, there is quite a lot of code in the step event. However, that is intentional and it actually doesn’t slow things down as much as one might suspect (if at all).

    Game Maker handles code pretty well, even if it has to interpret it; programmers shouldn’t shy away from putting a lot in the step event just because they think it will slow things down. You by no means have to use the step event as I did; however, there are a number of benefits to doing so:

    Complete control over order of events
    Instant access to most of your important object code
    Easily searchable
    Ability to control just how game maker handles event firing

    This is especially useful with platform games, since there is a lot of physics involved; and if one must go back and forth between thinking about the order of game maker events, clicking to and from them, etc. and deciding what to do and how to do it, it makes for a very tedious bug squashing process if it doesn’t end up working correctly the first time you run it.

    However, if it is all in the step event, you don’t really get much lag (in fact, try using the above example; you shouldn’t notice any lag at all), and you get to control when the player checks for a block, when he gets his new x and y position, etc.

    Hope I clarified some of this for you. If you have any other questions or concerns, either post it here and hope I remember to come back (lol) or head over to the Game Maker Community (link on the sidebar), and start a new thread in the Q&A forum linking to this article so they know what you’re looking at.

    Good Luck,
    Adam (SoulRed12)

  19. I’m still fairly new to game maker, so I’ve been trying out different people’s approaches to platformer character movement, and I have to say that of the 3 I’ve tried so far, this one is by far the nicest. Most of the others have a problem where the character either doesn’t quite touch the platform every time he lands, or he will stop in mid air just above the ground, then drift down the rest of the way until he makes contact.

    I did notice with this code though that the character can’t quite touch the walls when he’s facing left for some reason, yet the collisions are perfect when he’s facing right. Might this have to do with the mirroring of the sprites?

    In any case, is this something you’ve experienced, and if so, do you have any ideas how to fix it? I’m using version 7.0, and I think I followed your example correctly because everything else seems to work fine.

    Thanks.

  20. Hey! Great Guide! I’ve been trying to create my own and its just gotten way overcomplicated. lol

    Quick Question though… What exactly is the ‘Sign’ function, and what does it do?… I’ve been using Game Maker 6.1 for a while now, but I’ve never come in contact with that…

    Any help would be greatly appreciated! Thanks!
    Take Care!

  21. Hey guys,

    I usually don’t respond to questions here but since these ones aren’t overcomplicated I thought I’d go ahead and write back. ^_^

    @3dTestPattern: I don’t tend to experience this, but I can only guess that it’s something to do with the way your sprites’ bounding boxes are lined up with the sprite’s origin. If your sprite(s) either doesn’t (do not) take up the entire frame, or if they’re not centered and symmetrical, a perfectly centered origin probably won’t work.

    In this case, take a look at the bounding box numbers for the sprites, and for each origin, change the x value to halfway between the boundary’s “left” and “right” values. For example, if the bounding box’s left is 6 and right is 18, set the sprite origin’s x coordinate to 12. It might also be a good idea to check to make sure the bounding boxes are the same size (width and height) for each related sprite (such as each pose/action for the player); that may require setting the bounding box coordinates manually.

    @Cayce: The sign() function basically returns value/abs(value), which gives 1 if the value is positive, and -1 if the value is negative. Therefore, if you input sign(5) you get 1 and sign(-3) you get -1. sign(0) equals 0.

    Thanks for the compliments and I hope this helped you guys.

  22. So, this guide is awesome, thought I found it on the Game Maker forums. I was even able to implement Double Jumping without any prior knowledge of GML (I’ve had Game Maker 7 Pro for about..2 days now). With that said, I am having trouble (This is slighty off topic to be honest, so feel free to ignore my comment) getting blocks to move up and down/back and forth on their own. IE: Crossing a gap on an automated block, getting it to goto a certain Y or X value and returning to it’s origin only to repeat the process. I had it working in another engine that used Solids, but I refuse to go back to that method. Any help would be greatly appreciated it. Aside from that, this is quite the great engine. Thanks!

  23. WOW! really coo, tutorial, this is definetly something I will use
    to improve my collisions. No more ground penetration disabling my movement.

    Thank You!

  24. Hello

    Thank you i love all your tutorials (i learned gml with your tutorial) but theres one prob for me when i use this code. I copy and paste all of this code exactly make all the sprites centered and uncheck precide collision checkin i made sure tha the origin of the sprites is indeed in the middle of the player but one problem… i start the game i see my person on the floor in the jumping sprite and when i touch a button or something the game goes unresponsive and goes like a transparent grey and i have to use ctrl+alt+delete thing to close the game. I dont have any other code than this code and im usng game maker 7 pro

    thank you
    danny

  25. Try starting your character out in the air. If the character starts out stuck in the ground or ceiling, you’re going to have problems. Other than that, I can only suggest reading my article on debugging (you can get there from the “tutorials” tab) or bringing the question to the Game Maker Community (link is at the bottom of the article) with a copy of your game.

    Unfortunately nobody else is reporting an error like the one you’re reporting, so it must be an issue with your file in particular. That could mean an odd level design, oddly-shaped sprites, or something similar…so if you post your file on the Game Maker Community along with the details of your problem you’ll likely get the help you need.

    • i do always start him out in the air… is there anyway that i could attach my .gmk file here in this forum or somewhere where you could get to it and let me know what im doin wrong? thank you very much

    • i commented out this line of code …//We must move up until contact with the ceiling
      while (!place_meeting(x,y+sign(vsp),objBlock)) y+=sign(vsp);
      vsp=0… and it seems like the game runs its just that the player floats in the air

  26. My last piece of advice is to make sure your block objects aren’t solid. If they’re solid, they’re going to cause problems.

    And I’m sorry, but I can’t look at your file because I don’t offer that kind of support for my tutorials anymore. See question 2 of the FAQ for more info. Besides, you’ll get much better support on the Game Maker Community (where many different users will look at your file), which is why I suggested posting there.

  27. ok ill try that ty very much on all of your tuts!!!

  28. you also reply to your comments really fast… i like that dont have to wait 5 days to get a question answered

Leave a Reply