Hey guys, no update today. I just thought that today I'd make a quick post about spriting.
If you're reading this blog trying to learn something, then I'm guessing you are not the best at programming. If fate has smiled upon you, you probably are not very good at programming, but are an excellent artist. If so, good for you. However, if you are like me, you probably cannot draw to save your life. Being a good artist is a talent gained through time and practice. If you don't want to take that time and effort, there are alternatives. Not nearly as good alternatives, but still there.
One way is to use a sprite template. As mentioned before, I used one by Chumbucket, and it actually contains a ton of animations that you can use. I honestly don't know of any others, but editing pre-existing sprites is a possibility as long as your game is freeware.
For me though, it wasn't enough. While I have not shown them yet, the attack animations are actually edits of the template's graphics, for better or for worse, but I like to have at least a slight personal touch in what I use. Here are some pretty good pixel art tutorials I have read and learned a few tricks from. Again, these will not make you great artists, but they teach skills worth learning.
A tutorial by Derek Yu. A personal favorite artist.
http://www.derekyu.com/?page_id=218
A tutorial by The Mechanical Maniacs.
http://themechanicalmaniacs.com/guides/spriteguide.php#Type4
A collection of tutorials on Serebii forums. It's a pokemon site, but there are several good thorough guides.
http://www.serebiiforums.com/showthread.php?59110-Sprite-Tutorials-56K-Warning!
I tutorial by... gas13(?). He actually has several, and they are very thorough and well thought out.
http://gas13.ru/v3/tutorials/sywtbapa_almighty_grass_tile.php
One man's attempt to create a video game with nothing but Game Maker's GML and an idea in his brain. The end result might be terrible, but a learning experience in the end.
Friday, June 29, 2012
Wednesday, June 27, 2012
8: Mario Posing
Our character has a face now, but he has an odd tendency to run while jumping in the air. Fixing this next part is pretty easy. How do we stop Tanner from running in the air? How do you determine if he is in the air?
if place_meeting(x,y+vspeed,obj_floor)
{
move_contact_solid(270,vspeed)
vspeed = 0
doublejump = 1
inair = 0
}
else
{
vspeed += 2
inair = 1
}
There we go. No we have a variable we can call whenever we need to know if Tanner is touching the ground. Now all we need to do is use this in our animation code:
if (inair = 0)
then run and idle animation
else if (inair = 1)
then in air animation
If you're following along, you'll soon get to feel the joy of rearranging your code to keep it looking pretty as you add if statements. For now though, we'll just focus on the in air portion. This next portion is a little weird, mainly because I found a goofy way of doing it. First off, we can add:
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
}
We know that inair contains 4 frames, but each is intended as a completely different graphic.
Therefore the first thing we do is set the speed to 0. Next, we need to check if Tanner is actually rising or falling. We could possibly use prevy, but we have something else at our disposal that's very helpful, vspeed.
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
}
else if (vspeed > 0)
{
image_index = 2
}
}
We're almost there. Tanner is rising and falling, but he's always facing left. It's time to put face to use, but how? We could add more if statements, but it will look pretty cluttered, and be a bit repetitive (something that's going to be unavoidable later anyway, but stick with me). How about just adding face to image_index?
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
image_index += face
}
else if (vspeed > 0)
{
image_index = 2
image_index += face
}
}
Think about it. The variable face is always 0 for left and 1 for right. I arranged the frames in spr_tinair so that the first frame was left, and the second was right. Adding face works perfectly, and now that we know we can do this, we might be able to put it to use at some other point.
With that all done, our animation code (at least for movement) is perfect. Next time, I touch on some small debugging. And for completion sake, here's the full code:
if (inair = 0)
{
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
}
}
}
else if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
image_index += face
}
else if (vspeed > 0)
{
image_index = 2
image_index += face
}
}
Here's the gm81 file:
https://www.dropbox.com/s/70ubcxv1cb76ju6/8%20Mario%20Posing.gm81
Here's the executable:
https://www.dropbox.com/s/ddy7ztx0fcc4guz/8%20Mario%20Posing.exe
place_meeting(x,y,obj)
Jackpot, sorta. We could just as easily add this to our animation code, but I would rather avoid unnecessary checks when a variable will do just fine. Let's add a new one to the fold:
inair = 0
Then introduce it to our gravity code:
if place_meeting(x,y+vspeed,obj_floor)
{
move_contact_solid(270,vspeed)
vspeed = 0
doublejump = 1
inair = 0
}
else
{
vspeed += 2
inair = 1
}
There we go. No we have a variable we can call whenever we need to know if Tanner is touching the ground. Now all we need to do is use this in our animation code:
if (inair = 0)
then run and idle animation
else if (inair = 1)
then in air animation
If you're following along, you'll soon get to feel the joy of rearranging your code to keep it looking pretty as you add if statements. For now though, we'll just focus on the in air portion. This next portion is a little weird, mainly because I found a goofy way of doing it. First off, we can add:
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
}
We know that inair contains 4 frames, but each is intended as a completely different graphic.
Therefore the first thing we do is set the speed to 0. Next, we need to check if Tanner is actually rising or falling. We could possibly use prevy, but we have something else at our disposal that's very helpful, vspeed.
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
}
else if (vspeed > 0)
{
image_index = 2
}
}
We're almost there. Tanner is rising and falling, but he's always facing left. It's time to put face to use, but how? We could add more if statements, but it will look pretty cluttered, and be a bit repetitive (something that's going to be unavoidable later anyway, but stick with me). How about just adding face to image_index?
if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
image_index += face
}
else if (vspeed > 0)
{
image_index = 2
image_index += face
}
}
Think about it. The variable face is always 0 for left and 1 for right. I arranged the frames in spr_tinair so that the first frame was left, and the second was right. Adding face works perfectly, and now that we know we can do this, we might be able to put it to use at some other point.
With that all done, our animation code (at least for movement) is perfect. Next time, I touch on some small debugging. And for completion sake, here's the full code:
if (inair = 0)
{
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
}
}
}
else if (inair = 1)
{
image_speed = 0
sprite_index = spr_tinair
if (vspeed < 0)
{
image_index = 0
image_index += face
}
else if (vspeed > 0)
{
image_index = 2
image_index += face
}
}
Here's the gm81 file:
https://www.dropbox.com/s/70ubcxv1cb76ju6/8%20Mario%20Posing.gm81
Here's the executable:
https://www.dropbox.com/s/ddy7ztx0fcc4guz/8%20Mario%20Posing.exe
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
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).
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.
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. |
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
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:
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
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 |
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.
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.
Subscribe to:
Posts (Atom)

