How To

Better platformer physics

1

Seba06 2020-05-15 20:13 (Edited)

All of my games that involve jumping do them the same way, you move up until you reach a certain height or collide with something, then gravity pulls you down. But that feels stiff and robotic. How can I get better platformer physics both for when you jump and fall down a ledge while still being able to detect cell collisions and not clip through the floor?


nathanielbabiak 2020-05-15 23:43

In your main game loop, keep track of velocity (in addition to keeping track of character position like you're already doing).

Each time through the game loop, check if your character is on a platform. If they aren't, then decrease velocity by a small amount (i.e., gravitational acceleration).

When the player presses the key for "jump", immediately increment the velocity by a larger amount.

When the player is in the air, either due to a jump or falling off a ledge, continue to decrease velocity by that same small amount (acceleration). Lastly, make sure you have a maximum velocity limit, otherwise things might get going pretty fast.


nathanielbabiak 2020-05-15 23:51 (Edited)

There's one final thing, and it can get pretty complicated... Try implementing my previous response before addressing this one. After that is implemented, you'll notice that when the character is moving quickly, the image jumps by multiple pixels at once, rather than one at a time.

What you need to do is... "max out" the number of pixels you want to jump at most, then reverse-engineer the associated velocity variable value. That becomes your max velocity. But it gets even worse... here's an example to explain:

Suppose you decide a sprite jumping 3 pixels is acceptable, and the velocity variable value associated with this motion is 3.00. That only gives you a 3-to-1 ratio between your min and max velocity (from 3.00 down to 1.00). So, to increase the available velocities you can use, your minimum velocity needs to get below 1.00, which means that during some main loops, the sprite won't move even a single pixel.

You see where I'm going with this example? Now, in addition to determining the *max* velocity you're comfortable with (regarding pixel jumps), you'll need to determine the *min* velocity you're comfortable with (regarding *not* jumping pixels and how many WAIT VBLs you'll allow before the sprite movement looks jerky).

And, you'll need to implement this in your game loop in a way that allows non-integer velocities.


Seba06 2020-05-15 23:55

Thanks but that isn’t the problem. The problem is how we can let this velocity actually move the player and avoid the player from clipping into the wall. The method I normally use the detect the collision immediately breaks as soon as you are 1 pixel inside the wall (this can be seen in one of my videos by jumping in just the right way that you go directly inside the platform). If I let the velocity move the player more than 1 pixel at a time clipping will happen. One solution is to move it one pixel at a time and check if time if it collided with it but that could take up a lot of the limited CPU. I want to see if there’s a more optimized way to do it


Seba06 2020-05-16 00:01

I guess I could try making a system that always has the forces being applied even when there’s a cell in the way and it checks for a collision after it’s moved the sprite, if it’s inside a wall then it reversed the effects the velocity had in it. For this I would have to set a velocity limit to stop it from teleporting past walls. I’ll do some experimenting with it.


nathanielbabiak 2020-05-16 00:02

Every position needs checked for clipping. What you're asking for is an algorithm that checks intermediate positions without paying any clock cycle cost for doing so. Unfortunately, that's not possible. The check itself is inherent to the algorithm you're asking for.

Does my second post help at all? You could try developing games with max. velocity=1.00, and scaling downwards from there...


nathanielbabiak 2020-05-16 00:05

Depending on how you set it up, you might spend less clock cycles if you check for adjacency rather than collision. If you check for collision, you'll have to adjust by one position value *after you're done*. If you check for adjacency, you just stop the motion when you're adjacent.


nathanielbabiak 2020-05-16 00:06

Oh I just realized your collision check uses the HIT command. Bummer.


Seba06 2020-05-16 00:11

? I use cell.c to check specific cells of the level


Seba06 2020-05-16 00:12

I only use HIT when it’s sprite to sprite collision


Seba06 2020-05-16 00:19

what I’m saying is that it does the movement then it checks if it collided with with something, then it has to figure out what axis of the velocitity made it collide and undo the effects of it. What I’m worried about is how it’s going to figure it out because if I don’t want to end up with a bunch of spaghetti code. I might have to compromise and go for the “move it one pixel at a time and check for adjacency”


Timo 2020-05-16 10:18

You can check collisions for all positions between the last one and the new one. I guess you can do it separately for both axes (X and Y).

CURRENT_Y
VELOCITY_Y

TO_Y = CURRENT_Y + VELOCITY_Y
FOR Y= CURRENT_Y TO TO_Y
...check tile collision for Y
...if no collision... THEN CURRENT_Y=Y
...if collision then exit loop
NEXT Y


Log in to reply.