Tuesday, August 5, 2014

Lesson Learned: The Controls of Platforming

DISCLAIMER:  While I work on developing my first games, I will be making "Lesson Learned" posts.  All this post will be is me explaining code, so that I myself will better understand what I am learning.

I've been playing around with the tutorials for Game Maker and so far have covered the basics of the GUI as well as its Drag and Drop system of Programming.  However I decided the fist game I want to take a stab at is a platformer.  And the code is... well, new to me.

It appears to make a good platformer, you simply cant apply the drag and drop system.  You want to have control over all of the physics that go into the game.  Below is the code required to control keyboard inputs, collision, as well as gravity, all of which were applied to the object of the character.

///Initialize Variables
grav = 0.2;
hsp = 0;
vsp = 0;
jumpspeed = 7;
movespeed = 4;

The few lines of code above are applied to a "Create" event to the character object (as in, this code pops up when the object appears on the screen).

What these do is simply establish variables.  We set a value of 0.2 for the variable "grav", which will naturally represent gravity.  This variable will intertwine with our vertical speed variable ("vsp").  Naturally, as we dont want our character to be moving as the game starts, we are setting our vertical and horizontal speed to be zero, represented by "hsp" and "vsp".  The jumpspeed and movespeed variables are pretty self explanatory.  All of the variables we have established here will come into play with the next bit of code, which has been placed into a "step" event.  That is, every frame of the game will be checking this code.


Here is where the action takes place:

///Inputs
key_right = keyboard_check(vk_right);
key_left = -keyboard_check(vk_left);
key_jump = keyboard_check_pressed(vk_space);

//React to inputs
move = key_left + key_right;
//the above works as math. will equal zero when niether is being pressed
hsp = move * movespeed;
if (vsp < 10) vsp += grav;

if (place_meeting(x,y+1,obj_block))
{
    vsp = key_jump * -jumpspeed
}

//Horizontal Collision
if (place_meeting(x+hsp,y,obj_block))
{
    while(!place_meeting(x+sign(hsp),y,obj_block))
    {
        x += sign(hsp);
    }
    hsp = 0;

}
x += hsp;

//Vertical Collision
if (place_meeting(x,y+vsp,obj_block))
{
    while(!place_meeting(x,y+sign(vsp),obj_block))
    {
        y += sign(vsp);
    }
    vsp = 0;

}

y += vsp;


Now, this is where I'm having some trouble, so bear with me as I try my best to explain this bit of code in relation to the variables we had set before, and in relation to what will be going on in the game itself.

First off, we are setting a few new variables.  As it states at the top of the code, this is all taking the input of the player and applying it to our values that we have set.

key_right = keyboard_check(vk_right);
key_left = -keyboard_check(vk_left);
key_jump = keyboard_check_pressed(vk_space);

You can probably figure out what this is by just looking at it.  We are now assigning new variables to physical key presses.  So, whenever the right or left arrow key is pressed, it assigns a number 1 to the assigned variable, making it "true".  The reason we have assigned a negative value to the left key check will come into play further down the code.

move = key_left + key_right;
hsp = move * movespeed;

The above code is where these 1's and 0's get placed from the "keyboard_check"s.  As it is written, if key left is pressed, key_left becomes a 1, and if key right is pressed, key_right becomes a 1 as well.  This is why we made the Keyboard_check for the left key a negative value.  when -1+1 = 0, therefore if both keys are pressed, the move variable becomes false.  The character will not move.

The next line down, concerning the variable "hsp", observes the outcome of the addition we made and multiplies it by the movement speed of the character.  Again, if both keys are press, or no keys are pressed, the outcome is zero, and zero multiplied by 4 is still zero.

if (vsp < 10) vsp += grav;

This line applies our value for the gravity constant to our vertical speed.  In other words, if the vertical speed of the character becomes less than 10 (i.e. slowing down at the top of a jump), gravity kicks in, and the character will fall at the rate of gravity added onto the vertical speed (which we had set to 0.2).

if (place_meeting(x,y+1,obj_block))
{
    vsp = key_jump * -jumpspeed
}

This bit confused me at first, but its just an exercise in our boolean logic.  All this bit of code is doing is allowing the player to jump.  First, we need to remember that the "rooms" in GameMaker start with the origin of 0,0 in the top left corner.  Traveling down the screen or to the right of the screen results in positive x and y coordinates.  So, the place_meeting function observes which object your character is in contact with and where in relation to the character object.  In this case, we look at "y+1" being one pixel BELOW the character object, and it is coming in contact with the "wall" object I made, called "obj_block".

If that meeting place is true, that is, if the chaaracter is in fact sitting on top of a wall, then we allow the vertical speed to equal the inverse value of the jump speed (since we are jumping UP, our y value becomes a negative value), multiplied by the value 1 that is presented when the space key is pressed (using the earlier keyboard_check).  **Note:  For the space key, we had to use keyboard_check_pressed to ensure the jump key was not pressed the frame before the instance of the key press, ensuring the precision of timing.

//Horizontal Collision
if (place_meeting(x+hsp,y,obj_block))
{
    while(!place_meeting(x+sign(hsp),y,obj_block))
    {
        x += sign(hsp);
    }
    hsp = 0;

}

x += hsp;


Our final bit of code here is without a doubt the most important to every platforming game.  This establishes collision between the character and our wall.  So again, we observe the place_meeting function to see where the block lies horizontally to the character.  The expression "x+hsp" observes the pixels ahead of the x coordinate (which would be 4 pixels ahead).  If the block is within those 4 pixels, we enter our while loop.  The ! that has been placed in front of the place_meeting function negates the outcome, so in other words, this while loop will continue to carry as long as there is NOT an obj_block within 1 pixel to the right or to the left.  That's where the parameter "x+sign(hsp)" comes into play, as it observes whether hsp is +1 when travelling to the right, or -1 when travelling to the left, thus accounting for both sides of the character.  

As long as that remains true, that there is no block within a pixel of the character, then "x += sign(hsp)" will carry out, which just allows the character to move a pixel at a time.  Once that rule of the while loop is broken, we execute "hsp = 0", which just stops the character altogether.

Once the collision rule is set, its safe to run the variable x, allowing the character to move.

The last bit of code is the exact same for the horizontal collision, just negated to apply to vertical values we established beforehand.

So, after completing this lesson, I have my first result:



Obviously, GameMaker code needs some more exploring.  There is a tutorial for building a game of "Breakout" I will likely tackle next to better understand how to control and fine tune all of the physics and controls that go into these games.


My first full game will no doubt be a platform game.  I have some ideas hashed out but more will come when I can actually begin to build it.

Cheers.





No comments:

Post a Comment