Post date: Feb 07, 2016 10:13:14 PM
I wanted to make a special post about how jumping mechanics work when you're using a physics system in your video game. Truth be told, I don't really consider this an ideal situation. Ideally, you would want your 2D game to be simple enough to not have to resort to using Box2D to handle platformer physics. There are a lot of things you basically lose control over once you start using a physics system. In the rest of this post you'll see how we can manage a "Mario style" jump in the Box2D physics system. The ideal situation would have been to have my own physics system that is much simpler than the complicated system of forces and collision responses of Box2D where you don't really control anything directly. If I had managed to roll my own that worked well enough (none of my own could handle all the many active collisions that the gameplay in Hoard Lord necessitates) I could have handled jumping in a much simpler way. But, since this is a situation many of us find ourselves in in game development, I thought I would go over it.
The basic idea is this: in order to jump, the player must be standing over some solid object. Here are some "simple" approaches that most people will try in this situation that don't really work:
If we simply check his physics body to see if the bottom is touching anything, we will have all sorts of false positives and false negatives due to the uncertain nature of exact position values within a system physics system like Box2D, especially with so many bodies flying around as in Hoard Lord. In a physics system, a body will oscillate between being just above and directly on top of anything it "stands" on if there are any other forces at play - the amount will just be so small that the human observer won't notice. But this check will...
If we check only his vertical velocity, you will have situations (like at the apex of his jump) where he is airborne, but his vertical velocity has stalled, so he'll be able to jump again in mid-air.
Here is the outline of what we must do to make this feel natural to the player, and not allow "false positives:"
Create some number of "jump sensors:" physics objects that dont' actually collide with things, but can report when they would have collided with something. We attach these to the bottom of the player, slightly lower than his body.
When our sensor hits a solid object, allow the player to jump.
When our sensor stops contacting a solid object, remove the player's ability to jump if that was the only object in contact with the sensor.
So, by using these sensors we leverage the physics system's sanity checks and control of collisions to get reliable reporting on when the player body has begun or ended contact with another object that sits below him. There was a lot of trial and error in implementing this system. Here are some issues that came up:
Initially I had one "foot" sensor below the player, sized as the width of his body and protruding about 10% of his height below him. The problem using this was that it was allowing the player to almost wall jump because the sensor would detect very brief contact with objects at the extreme sides of the player - so when the player should have been brushing up against the wall that was registering as a ground touch and it was allowing him to multi-jump up walls of objects.
Next, I decreased with the width of the sensor. This removed the edge-touch problems, but created a new one: now if he was on the edge of an object he often couldn't jump.
So, at this point I created an additional "foot sensor" for the player: this one is almost as wide as the player, but only barely extends below him. This will allow him to catch edges but isn't as permissive as the other sensor. The other sense has now had it's width drastically reduced and protrudes much further than the other sensor.
This mostly worked, but I was still seeing some cases where the player could "edge jump" in an unacceptable way. So, I added one additional check before jumping: player vertical speed must be near-zero in order to jump. While this solution doesn't work on it's own, when coupled with these others it seems to do the trick.
Here's what the end result looks like - you'll see three boxes: the player's actual physics dimensions (largest pink rectangle), and two jump sensors at the bottom of his body, one wide that spans almost the width of the player body (highlighted red), and then a more narrow rectangle that protrudes further down than any of the others, but is more narrow (highlighted yellow).
You may notice that the top edges of his physics body rectangle have "cut off" edges. I "cut off" many of the edges of the rectangles when using physics systems because it smooths out something that you can normally see happen with these systems when lots of objects are moving across the each other - jittering when moving bodies encounter tiny edges of the other bodies and have their horizontal movement halted briefly. The best way I've found to mitigate this is to "cut off" the top edges of creatures, but leave their bottom edges intact. This way, they can still land on edges of things in order to be able to jump, but things moving across of the top of them won't "jitter." For stationary objects, though, I cut off all the corners.
Here are some more examples of what that looks like:
You'll notice that the cat has his own jump sensors. Also note that the "junk objects" have all of their corners cut off. This way, the player and the cat can smoothly run across the not-quite-aligned tops of a row of junk objects without losing momentum, and then jump away. The rounded corners combined with complete lack of friction means that objects will smoothly slide across each other without stopping, sliding up or down as necessary.
I hope this was interesting and even helpful - these are all extremely common problems that come up whenever you open the Pandora's Box of physics systems in your game. Every game is very different though: depending on the sizes, densities, and speeds attained by your objects the tweaking for all of these things will be quite different, but this basic approach works very well for Hoard Lord.