Pages

Monday, June 25, 2012

7: Run Tanner Run

Welcome back. Last time, we came up with some fancy new variables, and now, we've got to put them to use.

prevx
prevy
playerdir
prevplayerdir
face


I've already explained what these variables are for, but they aren't built into Game Maker. If we want them to do what we intend, we'll have to do it manually. The "prev" line of variables are just used to compare old variables to new ones. Therefore, to make them work, we just have to type:

prevx = x
prevy = y
prevplayerdir = playerdir


The most important part here is placement. We want to put the above code at the very beginning of our "Step" Event, before all our keyboard checks and the like. This way, the "prev" line of variables will be identical to the x, y, and playerdir of the previous frame. Then the rest of the code can mess with the current x and y, and we can compare them afterwards.

The next bit of code is actually going to be put into a new Event, called "End Step". Using "End Step" just guarantees that all movement and collision processing is done already, and all our animation code is applied to the correct situation. This next part is where I got a bit overwhelmed myself, but it's always important to take things one at a time. For now, let's start by checking the player's direction. Remember this statement?


if player is moving leftward
     set character sprite to run left
if player is moving rightward
     set character sprite to run right
if player is not moving
     set character sprite to idle


Ignoring the part about setting the character sprite, let's use this as a guideline:

if (prevx > x)
{
     playerdir = 0
     face = 0
}
else if (prevx < x)
{
     playerdir = 1
     face = 1
}
else if (prevx == x)
{
      playerdir = 2
}


With this done, we now have a piece of code that let's us ask about the player's direction and orientation, and then store that information into our two variables for later use. Unlike adding similar code to the keyboard checking, we're actually basing our information on what is happening instead of what we assume will happen. With this in our hands, the next part, actually changing the character's sprite, is fairly easy. Of course, I had to dig up some new variables built into Game Maker, and here they are:

sprite_index          //A non-numeric string variable that defines which sprite the object is using
image_speed         //A variable that determines the speed at which the sprite switches frames
image_index         //A variable that says which frame the sprite is on


These are fairly self explanatory, although I often find myself mixing them up. The only particularly odd thing to note is image_speed. The number in image_speed is the number of frames of animation per step (and default number of steps per second is 30 in Game Maker). In other words, you generally want to enter a fraction, or your animation will either skip frames or just play extremely fast. Anyway, let's get to coding:


if (playerdir = 0)
{
     sprite_index = spr_trunl
     image_speed = (1/3)
}
else if (playerdir = 1)
{
     sprite_index = spr_trunr
     image_speed = (1/3)
}
else if (playerdir = 2)
{
     image_speed = 0
     if (face = 0)
     {
          sprite_index = spr_tidlel
     }
     else if (face = 1)
     {
          sprite_index = spr_tidler
     }
}


The first two if's seem pretty straightforward. If the player is moving left, give him the left graphic and set his speed to one frame every three steps. If the player is moving right, do the same, but with the right graphic. The second is a little wierder, but not too complex. If the player is standing still, we set the image_speed to 0 (although a bit arbitrary, considering the idle graphics are one frame each. I think originally they were together, but I left it in anyway). Then we check his orientation, and set the graphic to the left or right idle graphic accordingly.

There is one other bit of code I want to add, if only for my own sake. It isn't anything too important, but some people may get annoyed if I didn't add this:

if (prevplayerdir != playerdir)
{
     image_index = 0
}


What does this do? Well, "!=" basically is the same as the NOT operator. In other words, if the player's previous direction is different from his current direction, then the animation gets set to the beginning. This is something that's barely noticeable, but without it, when the player switches from idle to run, or from left run to right run, they will continue mid animation. Again, not something too big, but I wanted to add it anyway.

Now that our hero can run, we have to teach him to stop running midair, and learn proper aerial form. Next time, we add rising and falling graphics to the mix.

Here is the gml81 file:
     https://www.dropbox.com/s/3sye6imavpflnet/7%20Run%20Tanner%20Run.gm81
Here is the executable:
     https://www.dropbox.com/s/5mxbbbzszjecynh/7%20Run%20Tanner%20Run.exe

Saturday, June 23, 2012

6: Think Ahead, and the Headaches Come

I'll be honest. Up until this point, I've known exactly what to do because I've read enough instruction books and internet guides to know exactly what to do. After finishing the movement aspect, I had to get creative and just start making it up as I went. This is the point where what I do works, but I secretly hope someone comes along and points out a more efficient way to program.

Today, we're talking about adding animation to our characters. I almost always see tutorials mention this aspect briefly, but never in depth. In all fairness, the reason for the lack of instructions for this sort of thing is probably the same reason as the lack of AI tutorials. Some code is going to be subjective not only to your game, but the way you program things. However, that's why I started this blog in the first place, so let's get started.

First, we need some graphics. I'm a terrible artist, but I want the graphics to at least look somewhat distinctive. Fortunately, I found a pretty awesome platform character template made by Chumbucket (he started a newer one, but I found the original to be pretty useful).

This is Tanner. He's pretty lame, I agree.
There's our exciting little hero, with his wife beater shirt, blue jeans, buzz cut hair, and a wooden sword. Not much to look at, but hey, that's not the point. He has 4 key graphics we want to apply: Idle, Running, Jumping, and Falling. Adding them into Game Maker can be a bit troublesome. Then again, arranging frames of animation can always be frustrating trying to get the frames to line up perfectly. It's possibly harder in Game Maker because you can only view one frame at a time when editing. Best I can recommend is to add the graphics in as best you can, and just take the time to adjust them later.





When I name sprites I tend to follow the same formula of spr_[object's first letter][quick description][suffix]. The formula seems a little convoluted, but I think it leads to short names, such as spr_trunr (or, sprite of Tanner, running right) that are easy to remember. You may also notice that I clumped the jumping and falling sprites together, both right and left, in the spr_inair. I actually discovered a neat trick later that let's me save some time doing this, but we'll get to that later.

We'll take it one animation at a time, starting with running. An easy fix would be to tack on a "change sprite" command to our horizontal movement code. The problem there is that the character would continue running unless you adding more code, probably along the lines of:

if keyboard_check_released(vk_right)
     set character sprite to idle right

Unfortunately, that creates more problems. Perhaps there is a genuine fix for this method, but I found a way I like much better. Instead of adding to the movement code, we'll add code to the "End Step" Event and do something akin to this:

if player is moving leftward
     set character sprite to run left
if player is moving rightward
     set character sprite to run right
if player is not moving
     set character sprite to idle


This is a bit vague. In fact, it almost seems a little obvious of a statement, since it's what we want ultimately. The question we should be asking is, how does the game know the character is moving left or right? In the earlier example, we used the fact that the player was pressing a key, but the game has no built in way of know the character's movement because we're just making it warp 8 pixels to the left or right instead of using the hspeed variable. There is a way, but first, we should add some new variables in the create event:

prevx = 0
prevy = 0
playerdir = 2       // 0 means left, 1 means right, 2 means neutral
prevplayerdir = 2
face = 1              // 0 means left, 1 means right


The "prev" variables are used for checking the character's movement. By comparing the old variable to the current ones, you can check for movement a little easier. For example, if you asked:

if (prevx < x)


Then you are asking if the character is moving to the right.  The playerdir and face variables are really for convenience, but we can put them to good use later on. There is already a built in direction variable in every object made in Game Maker, but it's degree based and may actually change based on the player's hspeed and vspeed. Playerdir is just called playerdir so I don't get the two variables mixed up. Face is similar to playerdir, but it's important to remember the distinction between the two. Face is about the character's orientation, while playerdir is about the character's actual movement. At this point, the difference is not too important, aside from the idle graphic, which while neutral in direction, can either be facing left or right.


I'm going to stop here for now. I apologize for the lengthy wait between posts. From now on, posts may be shorter, but they'll be more consistent. Thanks for your patience.

Tuesday, June 19, 2012

5: Jumping Complex

Before we go any further, I've decided to do something different as I go along. This entire time, I've just been  typing in instructions, and expected people to learn just by reading it, or by following along themselves. That's fairly unreasonable, so I've taken the time to add the .gm81 file and executable to the end of each post where I add code. The executable is there if you don't have Game Maker, and would only like to see the end result (and the glitches). The .gm81 is the source file Game Maker can read, so you can see exactly how I've set things up.

The reason I wasn't doing this before is due to the fact that I'm much farther along than what we've been over. Every example picture I've show, and code is actually me going back through an extra copy of the game and deleting anything we haven't discussed yet. All files are uploaded using DropBox, so you don't have to be attacked by ads and the like. I'd also like to apologize about the executable, as I'm running Game Maker Light. I plan on getting the official version eventually, but until then, these files have the annoying watermark.

Now back to our feature presentation.

The first thing I want to add today is double jumping, but this time, I want the player to be able to do so once. Let's bring up the old code.


if keyboard_check_pressed(vk_up)
{
     if place_meeting(x,y+1,obj_floor)
     {
          vspeed = -27
     }
}


If we look at how our jump code works right now, it only works if the character is on the ground. In order to make sure it works in the air, we need to add an exception.

if keyboard_check_pressed(vk_up)
{
     if place_meeting(x,y+1,obj_floor)
     {
          vspeed = -27
     }
     else if something                                                // exception
     {
          vspeed = -20                                                 // double jump is weaker due to personal preference
     }
}


What exactly is this exception? Well, how about a variable? We can call it doublejump. When the player touches the ground, the variable becomes 1. When the player jumps midair, the variable becomes 0.


if keyboard_check_pressed(vk_up)
{
     if place_meeting(x,y+1,obj_floor)
     {
          vspeed = -27
     }
     else if (doublejump == 1)
     {
          vspeed = -20
          doublejump = 0
     }
}


if place_meeting(x,y+vspeed,obj_floor)
{
     move_contact_solid(270,vspeed)
     vspeed = 0
     doublejump = 1
}
     else
     {
          vspeed += 2
     }


Typing all of this will technically work, but we've got one last thing to do before it works. If you decide to make your own variable (and believe me, you will often), you have to declare it. So in the Create event, add a script that simply says:

doublejump = 1


The number is irrelevent here. Any custom variable must be declared in the create event. If you didn't do that, as soon as the game attempts to do anything with the variable, it declares an error and shuts down.

The next element I want to touch is Dynamic Jumping. If you've played quite a few Platformer games, this is an element you see all the time, but rarely think too much about. We want the player to be able to control their jump height based on how long they hold the jump key. First off, let me introduce a new command.

keyboard_check_released(key)


What we want to do is program so that when the player releases the up key, they stop their upward momentum.

if keyboard_check_released(vk_up)
{
     vspeed = 0
}


That would work, right? Well, not really. If the vspeed becomes 0 instantly every time the player lets go of the up key, the character would stop in midair, even if they were falling. So let's double up the conditions just like we did with the basic jumping code.

if keyboard_check_released(vk_up)
{
     if (vspeed < 0)
     {
          vspeed = 0
     }
}


The "vspeed < 0" condition checks if the character has upward moment before stopping the vertical movement. This does need to be adjusted a bit though, as the character's jump will appear a tad jerky. I want the character to still rise slightly after the key is released, so I want the vspeed to be set to -10.


if keyboard_check_released(vk_up)
{
     if (vspeed < 0)
     {
          vspeed = -10
     }
}


This brings up one final, easy to fix problem. If the player releases the key when their vspeed is between -10 and 0, they will actually gain jump height. In order to remove this, we just change:


if keyboard_check_released(vk_up)
{
     if (vspeed < -10)
     {
          vspeed = -10
     }
}


And there we go. With that out of the way, we are completely done with movement, at least for now. Next, we add some actual graphics, and turn our little rectangle into a real boy.

Here is the Game Maker file:
     https://www.dropbox.com/s/7ylg2uhvucq4hrv/5%20Jumping%20Complex.gm81
Here is the executable file:
     https://www.dropbox.com/s/ovezllkl6cnkqrj/5%20Jumping%20Complex.exe

Sunday, June 17, 2012

4: Polishing Up Gravity

There's nothing more thrilling than figuring out how to program something, then finding out it's buggy as hell and having to spend hours making it work perfectly. It can be an endless source of frustration, but a game that feels buggy and unpolished is going to be quickly shutdown and put in the Recycle Bin, no matter how much content you put into it.

Before we get to the nitty gritty though, I think we should address the huge issue staring us straight in the face, namely that our main character is able to jump in the air infinitely. Let's Review:


if keyboard_check_pressed(vk_up)
{
     vspeed = -27
}


It's a pretty basic command, with a pretty simple solution to our problem. If we don't want him to jump in the air, then we just have to make sure he's standing on the ground.

if keyboard_check_pressed(vk_up)
{
     if place_meeting(x,y+1,obj_floor)
     {
          vspeed = -27
     }
}


Yup, just add a second if statement checking if the player is touching the ground. There is another way to write this, using the "AND" statement. Doing so saves space, but I wrote it this way for something later. For now, we need to deal with another big problem. Right before landing, the character jitters to the ground.


if place_meeting(x,y+vspeed,obj_floor)
{
     vspeed = 0
}
     else
     {
          vspeed += 2
     }


If you want to fix the problem, you need to figure out what exactly is causing it. In this case, just think it through frame by frame:

x = distance from floor
Every frame, the game checks the character's falling speed, and checks to see if in the next frame, he'll move into the floor. If he is, the game removes his vertical speed. This means that the next frame, the code checks the character's vertical speed again... which is now 0. If the vertical speed is zero, and the character isn't standing inside the ground, he'll fall again. It does this several more times until the character is finally on the floor. This brings up two big problems. The first is getting the character to stop freezing mid-air. The second is fixing the collision check so the character doesn't have to stand INSIDE the ground.

The first is actually pretty easy to fix, thanks to a really handy command built into Game Maker:


move_contact_solid(dir,maxdist)


I love this command. Basically, it moves the object right up against the nearest solid in the direction you type. For the direction, you have to type a number, as in degrees. So for us, we need down, which is 270 degrees (if you haven't done much geometry, just remember 0 is east, 90 is north, 180 is west, and 270 is south). The second argument it wants is maxdist, which in this case, we just use the vspeed variable.


if place_meeting(x,y+vspeed,obj_floor)
{
     move_contact_solid(270,vspeed)
     vspeed = 0
}
     else
     {
          vspeed += 2
     }


Doing this fixes the entire problem. This character no longer jitters right before touches the ground. I'm sure this perfect programming won't come back to bite me in the butt later.

Foreshadowing!


Anyway, let's take a step back and finally give our walls some kind of purpose. We won't worry about "move_contact_solid()" in this case, if only because it's not noticeable at all.



if keyboard_check(vk_right)
{
     if not place_meeting(x+8,y,obj_wall)
     {
          x += 8
     }
}
    else
    {
        if keyboard_check(vk_left)
        {
             if not place_meeting(x-8,y,obj_wall)
             {
                  x -= 8
              }
          }
     }


Okay, so this part looks like a horrible mess of brackets and if statements. This is only a small sign of how crowded the if, then's can become, so learning to read this is important. Just remember when typing these, to do like I do and line up corresponding brackets together (or something else if you format code differently than me) so you can keep track of everything.

Well, there we go. Now we've got the bare basics of mobility covered. Next though, we give our character the ability to double jump ONCE, and let the player control the strength of the jump.

EDIT:
     This is the Game Maker file:
          https://www.dropbox.com/s/shkliu9jnvzfw13/4%20Polishing%20Up%20Gravity.gm81
     This is the executable:
          https://www.dropbox.com/s/a47hichwe2z0lup/4%20Polishing%20Up%20Gravity.exe

Saturday, June 16, 2012

So Sleepy

Well, no progress to be made for today. Today, I got to ride in a packed van for 14 hours, getting home from vacation, and now I'm feeling pretty tired.

Unless I'm unable to post, I'll be adding to the blog daily, or at least every other day. Any new progress with the programming will have a number next to it, that way newcomers won't have to dig through pointless posts to find what they really came for. The rest is just filler, but I'll try and post about relevant things, such as small guides I found helpful or indie games that showcase Game Maker's abilities.

Except for today. Today, I sleep.

Friday, June 15, 2012

3: Rise and Fall

Well, now that the rectangle can move horizontally, it's time to tackle the signature aspect of platforming games, jumping. It only gets more complex from here, but we've got to get the basics down before we can tackle the good stuff.

Before we even touch the up key and jumping though, I want to tackle falling. After all, if you let the character jump, he'd continue on to infinity. You may have noticed that early on, I placed the player pretty high up. I did so to test gravity. Let's approach this just like we did last time, shall we? All of this code can go just below last post's code.

Gravity exists.


Er... well, sure, but what is gravity? A force that constantly pulls objects towards the ground is about as simplistic as I can put it. We're not programming realistic physics here, so all we need to do is code so that the player acts like gravity is affecting him.

vspeed += 2


There we go. Vspeed is a handy variable built into every object Game Maker creates. It adds the vspeed variable to the current y of the object every frame. Adding to the y means the object shifts downward, and as an added bonus, by constantly adding to the vspeed instead of just setting it to 2 or just adding to y manually, the character falls faster every frame. Problem solved, right?

Er...




Okay, so all we did was make the poor guy plunge into the center of the earth, but hey, you have to start somewhere. I think you know where this is going.

When character touches the ground, STOP!


Don't forget, IF, THEN.

if the character touches the ground
     then stop him from moving down


This seems like a pretty simple command, but for me, it's another moment where I had to search around the help files, looking for the commands I wanted specifically. The command is "place_meeting(x,y,obj)". Basically, this function checks if there would be collision between the object it is written in, and the object written at "obj". The catch here is that it checks for a hypothetical collision, assuming that the object it's typed into was placed at the x and y you type in. It may be easier to understand if I gave an example.

if place_meeting(25,35,obj_wall)


In other words, if the object was placed at the coordinates 25,35, would it collide with the wall?

For us though, it gets even more complicated.

if place_meeting(x,y+vspeed,obj_floor)
{
     vspeed = 0
}
     else
     {
          vspeed += 2
     }


Want to know why exactly I typed "(x,y+vspeed,obj_floor)"? Well, x and y were entered to keep the collision check relative to my position and added vspeed to y. This literally means it's checking for a collision vspeed pixels below the character's position.

There we go then, our happy little rectangle can now fall daintily onto the floor. Unfortunately, it's trapped on the ground until we teach it to jump. This is the easy part. Think about it for a second...

if player presses up
     then give him upward momentum


Now translate:

if keyboard_check_pressed(vk_up)             // pressed prevents player from holding down the key
{
     vspeed = -27                                          // number is whatever you want, I just liked how 27 felt
}


With that, the character now has the ability to move around by moving, jumping, and falling. We did good, right?

Right?





If you try and type the above commands into Game Maker they will work, but you'll immediately notice several issues. For one thing, your character jitters right before landing on the ground, and for another, you can jump infinitely. Even by B-grade game standards, it's pretty abysmal. We have to fix these issues, but for now, take a moment and try to figure out how to do so yourself. Next time, we fix the choppy platforming, and finally stop the player from walking through the walls.

EDIT:
     Here is the Game Maker file:
          https://www.dropbox.com/s/1xug8y6z276buyv/3%20Rise%20and%20Fall.gm81
     Her is the executable:
          https://www.dropbox.com/s/g0wwrwmfktqnhqz/3%20Rise%20and%20Fall.exe

Thursday, June 14, 2012

2: Goodbye Drag n Drop

Now that we've got a basic set up, let's get to the real stuff. Today, we're going to make our special little rectangle move to the left and the right. Nothing difficult, but it's still a challenge for first timers. First things first, we open up obj_tanner's interface and drag an "Execute Code" action into a "Step" event. I can easily recall the next moment in my mind.


Every time I see this, my mind goes just as blank.
I'm not an idiot. I know what kind of commands I need to type. Unfortunately, I have no idea what exactly those commands are, or what way I need to type them. It's a little sad to admit, but I spent about five hours reading guides just to get a general idea of how to program, and find all the command lists. Before I spit out the commands, let's think what we want to accomplish.

Let the player move their character right and left


Very simple command, but the computer doesn't speak English. Computers talk in IF, THENS, so let's translate a bit.

If the player presses right or left
     Then move their character right or left


Getting closer, but if you translated that to GML literally, the character is going to move randomly left or right if the player presses either button.

If the player presses right
     Then move their character right
If the player presses left
     Then move their character left


There we go. Programming is an endless stream of IF statements, so you'd better get used to them. Next, let's actually use some GML commands.

If keyboard_check(vk_right)
{
     Then move their character right
}
If keyboard_check(vk_left)
{
     Then move their character left
}


Okay, the way I typed it isn't how it has to be written, but I like typing it C style, since it keeps things nice and orderly. As you can probably guess though "move their character" isn't a legitimate GML command. There are built in "movement" functions within GML, but sometimes the easiest solution is the best.


If keyboard_check(vk_right)
{
     x += 8
}
If keyboard_check(vk_left)
{
     x -= 8
}


If the newest addition doesn't make any sense, the command "+=" adds the following number to the preceding variable. In other words, add 8 to x. So in layman's terms, as long as the player is pressing right, it constantly adds 8 to the character's x placement, warping it to the right, but at 30 frames per second it looks like it's moving fairly smoothly.

There you have it. The most basic of commands, and something anybody who has made games before can do without a second thought. I still wanted to linger on it, just for the sake of showing some basic logic used in programming.





Whether you're following along in Game Maker, are pretty old hat with programming, or are just that perceptive, you might have noticed a big problem with the above code. If you didn't notice it, look at it again, and think (and no, it has nothing to do with the walls).

Think you've got it? Try tapping both the left and right arrow keys at the same time.

If you press both keys at the same time, both IF statements are performed. It's not a terrible problem, especially considering we're only adding and subtracting from the character's x, meaning pressing both keys just freezes him in place, but if more complex movement elements such as acceleration were used, it could really cause some bugs. There's an extremely easy fix for this though, and it is only one word.



If keyboard_check(vk_right)
{
     x += 8
}
else
{
     If keyboard_check(vk_left)
     {
          x -= 8
     }
}


With the else command entered, the computer always ignore the left key if the right key is already held down. Problem solved. Join me next time when we add gravity to the mix, and teach our little rectangle to jump.

EDIT:
     Here's the Game Maker file:
          https://www.dropbox.com/s/ak8gt8pi63wml2x/2%20Goodbye%20Drag%20n%20Drop.gm81

     Here's the executable:
          https://www.dropbox.com/s/48aoltwaf7s1lys/2%20Goodbye%20Drag%20n%20Drop.exe