|
Show Index |
|---|
Many newcomers struggle with the concept of adding the force of gravity to objects in
their game as well as figuring out how to make a game character 'jump' lifelike. The
biggest reason for this is because they don't realize that they need to account for TWO
physical forces to simulate gravity. Often they'll make a game character fall simply
by adding a negative value to the characters vertical position; such as PlayerPosY = PlayerPosY - 1. This appears to work at first,
for the first 2 or 3 game updates, until they realize that the character falls at a
constant (slow) rate of descent, which then of course looks unnatural.
Here's a little Physics 101 concerning the simulation of gravity. We'll consider the
case of gravity being applied to a players character in a game.
In the code shown above, although the programmer applys a VELOCITY to the character (- 1), he fails to apply an ACCELERATION.
He needs to apply both forces, velocity and acceleration. In the following examples
we'll call them YVel and YAcc. By the way, most of
the time the variables involved in your gravity calculations will have to be floating
point variables (not integers) since a lot of small calculations are typically performed,
especially since you're often increasing or decreasing an objects position by just
fractions of a pixel (or whatever units you are using), so your variables will all need to
have the 'floating point' suffix (the number symbol: #).
Every single game update, you must apply a VELOCITY (YVel#)
to the character, regardless if the game player actually pressed the 'jump' button or
not or if the game character is actually falling or not.
PlayerPosY# = PlayerPosY# + YVel#
Now most of the time the velocity will just have a zero or near zero value, meaning that
the players character won't actually move up/down (much). We don't usually directly
modify the value of YVel (unless we are simulating jumping, but we'll get to that later).
What we do is apply an ACCELERATION to YVel in order to make it change.
Acceleration is usually a constant rate (but that doesn't mean you couldn't design a game
that has variable rates of acceleration, i.e. force of gravity on different
planets). If we were talking real world physics, here on Earth acceleration equals
9.8 meters per second per second (that's 9.8 m/s2). But in some games
we're not looking for realism, so the acceleration constant just needs to be a value that
fits your game. i.e. maybe 5 m/s2, or 17 pixels/s2.
In our example here, we'll use 30 pixels/s2 and we'll use a variable to keep
track of it: YAcc# = 30
FALLING
We apply acceleration to the velocity like this:
YVel# = YVel# - YAcc# * timeElapsed#
Oh yeah, acceleration is dependent on TIME, so we must multiply acceleration (YAcc#) by the time (timeElapsed#) that has elapsed since the last game update so that the object falls the correct distance for the amount of time that has passed (less time, less distance... more time, more distance)
So, on the next game update if the game was updating at 60 times per second the time
elapsed would be .0166667 seconds. Using our example of 30 pixels/s2, the
velocity would increase by .5 pixels.
YVel# = YVel# - YAcc# * timeElapsed i.e. (YVel# = 0 - 30 * .0166667) i.e. (YVel# = 0 -
.5) i.e. (YVel# = -.5)
Obviously this half a pixel would be rounded up or down and we might not actually even
notice a change in the characters position on the screen on the first game update (keep in
mind that only .0166667 seconds have passed!), but on the NEXT game update, we will
definitely start to see things happen.
Every single update, we apply the characters velocity to his position (let's say he's
currently at Y=100):
PlayerPosY# = PlayerPosY# + YVel# i.e. (PlayerPosY#
= 100 + -.5)
Now at this point, the game logic has to compare the characters position relative to any objects or platforms that the character may be directly in contact with. If the logic determines that by moving the character down the distance that YVel# will move it (.5 pixels), it would push the character through an object or platform, then the game has to subtract the difference from what would have been the players new position (in our example here, .5 pixels lower at 99.5) and the top of the object or platform (move it BACK up to 100, if the top of the platform was at 100). Also we would have to set YVel# back to ZERO since the character is no longer falling.
Often if the character is already standing on a platform, that's exactly what happens (character collides with the platform directly below it) and the character REMAINS standing on top of the platform. This is similar to how gravity works in the real world. Even though you're not falling as you read this, gravity is still PULLING YOU DOWN. That's basically what you need to happen in the game. Gravity pulls the character down, the platform 'pushes' the character back up. If by chance the character had stepped off of the platform he was previously on, then gravity would now begin its magic and actually start pulling the character down (no platform to hold him up). Continuing on with our example, let's assume that the character didn't collide with anything .5 pixels below him:
Now we are at the second update since the character 'fell' half a pixel (YVel = -.5
with YAcc = 30) and we are about to apply acceleration to the characters velocity once
again:
YVel# = YVel# - YAcc# * timeElapsed#
So, now on the second update YVel will be increased yet again by (30 * .0166667) or .5
pixels making YVel now total (-1) pixel.
And once again, we apply the characters new velocity to his current position:
PlayerPosY# = PlayerPosY# + YVel# i.e. (PlayerPosY#
= 99.5 + -1) i.e. (PlayerPosY# = 98.5)
And we would definitely now see a change onscreen in the characters vertical position
since he would have now moved a TOTAL of (-1.5) pixels.
We check once again if the character collided with anything... (we'll say he didn't)
At the third update, we apply even more acceleration to the velocity, increasing it now to (-1.5) pixels.
We apply the new velocity to the characters position, moving him down a total now of 3 pixels.
Check for collisions.
Increase velocity again. (now at -2)
Apply velocity to characters position again. (now 5 pixels lower than from where he began to fall)
Check for collisions.
And this process repeats, over and over, ever increasing the characters vertical speed
until the game finally determines that the character has collided with something (let's
say he did, at Y=95). At that point, we back him up a bit to the height of whatever
object/platform he collided with, and we set YVel# back to ZERO (because he's no longer
falling!).
YVel# = 0
Any following game updates to PlayerPosY will have nearly zero effect again:
YVel# = YVel# - YAcc# * timeElapsed i.e. (YVel# = 0 - 30 * .0166667) i.e. (YVel# = 0 -
.5) i.e. (YVel# = -.5)
PlayerPosY# = PlayerPosY# + YVel# i.e. (PlayerPosY# = 95 + -.5)
And since he's still standing on a new platform (at Y=95), we notice the collision with it
and move him back up to where he should be (PlayerPosY# = 95)
And that's basically how you apply gravity. I've drawn it out rather lengthily across this whole page, but it's actually just a two step process:
1) Add Rate of Acceleration to current Velocity
2) Add new Velocity to current position
JUMPING
Now the REALLY cool thing about applying gravity to a game object is that if you want to create the ability for a game character to be able to JUMP UP, nothing really has to be rewritten or changed. The gravity code will take care of it for you AUTOMATICALLY.
Here's how it works: You simply apply a POSITIVE velocity (notice above we've always
been applying NEGATIVE velocities) to the game character at the moment that the player
presses the jump button. The exact amount of velocity to add depends on your game,
but going with the examples above, lets just say we'll use a nice number like 5 (pixels)
as the jumping force.
YVel# = 5
NOTE: We would only add the JUMP FORCE to YVel# if the game character was currently
standing on a platform, unless of course, your character can jump in mid-air...
The following game updates to PlayerPosY will automatically DECREASE his upward velocity,
and eventually bring him back down:
YVel# = YVel# - YAcc# * timeElapsed i.e. (YVel# = 5 - 30 * .0166667) i.e. (YVel# = 5 -
.5) i.e. (YVel# = 4.5)
Tracking the characters vertical position over a few game updates would look like this
(assuming he started at Y=100):
100, 104.5, 108.5, 112, 115, 117.5, 119.5, 121, 122, 122.5, 122.5, 122, 121, 119.5, 117.5,
115, 112, 108.5, 104.5, 100
19 game updates later, the character would land exactly back down on the platform he jumped from. His motion from jump to landing would look natural and give that momentary mid-air pause as he reverses direction at the pinnacle. And really that's all there is to it. If the character didn't land back on the platform it had jumped from, the gravity simulation would just continue to force him down faster and faster (95, 89.5, 83.5, 77, 70, etc.) until he eventually collided with something else (or fell offscreen...).
Isn't it nice when one piece of code just automatically applies itself to other elements of your game?
By the way, if you're looking for that Mario style jumping (where the longer the player holds down the jump button, the higher Mario jumps), it's fairly simple to tack on. After the player has jumped, all you have to do is check if the jump button is still being held down on the next game update. If it is, then set YVel# once again to the positive jump velocity (5, in my example) and calculate accordingly. If it's still pressed down at the following update, set YVel# once again back to the max positive velocity. Continue to do this until the player either has released the jump button, or too many updates have occurred since the player initially jumped (say, like 5 updates). After that, just let the physics calculations take over to decrease YVel# naturally. The players character will jump extra high due to the increased time spent moving upwards at the maximum positive velocity.
Now, a track of the characters position might look something like the following (let's
say the jump button was held for 3 updates):
100, 105, 110,
114.5, 118.5, 122, 125, 127.5, 129.5, 131, 132, 132.5, 132.5, 132, 131, 129.5, 127.5, 125,
122, 118.5, 114.5, 110, 105, 99.5(or hit the ground again at 100)
So there you go! I hope that helps! ;)
| If you've reached this page and there's no index on the left, Click here to show the Index Page | |