For Kobold Kit (the Sprite Kit game engine) we’re working on Super Stick Spy, a 2D platformer game. Like so many others, we started out using the (Box2D) physics engine that’s so neatly integrated in Sprite Kit to get everything up and running quickly.
But we knew full well that for the final product, we’ll have to scrap the physics engine altogether and follow best practices when it comes to platformer-programming.
Now with the demo version nearing completion (see video) I can tell you in full detail why you don’t want to use a physics engine for a 2D platformer!
Moving Platform Hell
A moving platform with physics needs to be a dynamic body. Don’t even try moving static bodies, at least in Box2D that will end up in jumpy movement of the body. Though kinematic bodies work better (if available).
The player or other game characters standing on a moving physics body will have the platform slide underneath their feet. The characters won’t magically move along with the platform! And there is no feature in the physics engine that lets you set this up. You have to program it to synchronize character movement with the platform they’re currently standing on, and end the synchronization as soon as a character lifts its feet up from the platform.
Which can be a problem for downward-moving platforms as the player loses contact with the platform every other frame, starts falling, and lands right back on the platform. To put it in Homer’s words: “Doh, doh, doh, doh, doh, doh, doh …”. So you need to make the character stick to the platform, yet allow him to fall off of the ledges and jump, and possibly also allow him to be forced off the ground by normal collision events (projectile impact, platform moving through a tiny crevice).
If the moving platform follows a path but hits an obstacle, it is no longer guaranteed to follow the path exactly. In fact since it is a physics body, any external force acting on it will make it deviate from its preset path – including the player landing on it! This can only be prevented by calculating the position of the platform based on the current path segment’s end points and by considering what percentage of that segment the platform must have traveled based on current time and/or movement speed. Don’t try to do this the simple way with actions or position+velocity integration.
If there is any chance of the platform getting other characters stuck between collisions, like a lift dropping all the way to the floor, you need to prevent this situation. Otherwise the stuck character may be forcefully repositioned by the physics engine. That character could end up in completely blocked space, or on the other side of a blocked door, or on top of the lift or to the sides of it.
Walking on Sunshine, Not
A common issue with physics engines is that they treat the corners of bounding boxes as just as solid (rigid) as the rest of the bodies’ bounding box. Therefore characters can easily get stuck in areas where differently angled slopes meet. Fortunately Box2D has chain shapes with which this problem can be prevented through specifying “neighbor” points. But this is tedious to setup.
Furthermore, walking along a slope will always have characters with rectangle bounding boxes slide up in the air. Walking up a 30° slope to the left means only the lower left corner of the bounding box will meet with the slope, which leaves the center and bottom right areas of the bounding box high above the ground:
The only way to force a character to walk with his feet on the ground is by purposefully giving the collision shape for the slope a one-tile offset to the right. That of course only works if your tile sizes and player sizes match. Plus it makes designing levels and generating collisions from it so much harder.
In turn, if you move along a slope downwards, the character won’t just slide down on it. The steeper the slope, the more it will “bunny hop” downwards rather than slide. This just doesn’t look good, and it causes issues with other aspects of the game. Say you don’t allow the player to jump in mid air – that then makes jumping while walking down a slope completely unreliable without extra code counteracting against this.
Tilemap Collisions Ain’t Easy
You’d think that every tilemap tile being a rectangle, you could simulate physics collisions by generating a box for every tile. Nope.
Not only is this incredibly wasteful, both memory wise and runtime performance (collision detection). It will lead to the aforementioned movement problems where moving bodies get stuck on edges. And by edges I mean any two boxes sitting next to each other, forming a seemingly straight line. Yet the character can get stuck trying to move across these boxes.
To properly create physics collision shapes for tilemaps you need to apply contour tracing (Moore algorithm) like the solution I implemented in KoboldTouch. This generates paths forming the contours of a tilemap, and from those paths you can more easily create the necessary chain shapes for smooth movement across even surfaces.
In a custom platformer physics engine you’d simply check each character’s surrounding tiles with CGRectIntersect tests and then determine whether a contact occurs or doesn’t. You essentially analyze and respond to what’s happening in the tilemap collision-wise as the character moves along rather than having to pre-generate the collisions.
The latter creates an interesting problem: if tracing contours and creating physics shapes is costly, how do you open blocked doors for instance? In a physics world, you’d have to add an extra blocking body and subsequently remove it. In custom tilemap collision detection routine you’d simply detect that the previously blocking tile has been replaced with one that isn’t blocking (or removed altogether).
Physics contact detection is expensive
With a physics engine contact and collision detection just works. This is the good part. You can get going quickly.
However as levels grow in size, complexity and number of interactive objects, the physics engine will slow you down. You may need to put all physics bodies outside the visible screen area to sleep.
And then most contact tests really are just rectangle intersection tests. You can do the same just as well with CGRectIntersect. Especially if you consider you’ll have to write custom contact code anyway for things like slopes.
Just as problematic is how physics engines filter out contacts. You have contact, collision and category bit masks. They’re easy to confuse, so you may end up not being able to pick up powerup items because you forgot to set the flags in both the character and the powerup item correctly. You could as well let all contact events go through, and then look at the contacting object’s types to determine whether to ignore the contact or not. But this wastes the performance enhancing effect of using filters in the first place to prevent unwanted contact events from spamming the system.
With custom, rectangle intersection based collision detection you can typically create an easier to understand and faster contact event system.
Physics are alwaaa-a-a-ays glit-tch-tch-tch-y
This is just stating the obvious: you can never entirely prevent (or foresee) all possible physics engine glitches. Fortunately these effects are much less pronounced than they used to be, at least in 2D physics engines.
But still, you could end up with stacked bodies never coming to rest. Squeezed bodies tunneling and being repositioned elsewhere from one frame to the other. Joint connections being stretched far beyond reasonable and blocking pathways or worse, “exploding” everything touching them to extreme velocities.
Due to the dynamic nature of physics engines, and the fact that you most certainly didn’t write the physics engine, makes it quite difficult to debug such issues. And it rules out all “offset” type movement because you have no guarantee that the current position is the correct one to begin with.
There’s got to be a speed limit on everything
Due to the potential glitches but also because of falling bodies accelerating indefinitely, you have to put a velocity cap on every moving object. There is hardly a way around it, and hardly an easier way to prevent most glitches or at least soften their impact on gameplay.
Under no circumstances should you allow any body move faster than the speed it could reasonably move at. Otherwise such objects could simply bypass collisions (in science you’d call this effect quantum tunneling).
That means touching and comparing many body’s velocities every frame, before the simulation (world step) occurs. In a custom platformer physics the velocity cap would be an inherent aspect of moving a character in the first place.
Tweak the hell out of this world
In a physics world, bodies influence each other through collisions. If you change one aspect of one body (ie mass) this will affect other bodies it contacts (ie higher escape velocities). You can not make changes in isolation, you always have to consider that for every physics property you change on one body, all the other potentially interacting bodies will be affected by this change.
In custom platformer physics you usually ignore certain properties based on object types and what not. You don’t actually have to make a crate heavier if you want to make it accelerate downwards faster. You would instead simply change its gravitational factor, but collisions with other objects won’t be influenced unless you purposefully consider the impacting object’s speed.
So a custom platformer physics allows you to selectively apply only the properties that need to be applied in a specific situation. In a physics engine world, you can’t really do that. Building a world with a physics engine is the equivalent of building a house from a deck of cards rather than building one out of Legos.
Speaking of Movement
Have you played any platformers lately? Do any of those characters jump, walk, run, roll, fall, crawl, etc. like a physics object does?
No. Therefore at least the player’s own movement behavior needs to be severely customized in a physics world. In a way that you may end up taking over every aspect of the player’s movement from the physics engine. And when you do that, but you still have the physics body attached to it, more glitches can occur.
For example when two bodies impact each other, their velocities are used to calculate the outcome of the collision. Now if you move a character manually and end up only updating the position property, the physics body’s velocity may fluctuate every frame because the physics engine keeps trying to accelerate the body in the direction of gravity. That means you could end up with very weird collision behavior.
Fighting these effects gets worse when you want to implement features like wall-sliding or wall-jumps. Or allowing the character while jumping to slide along the ceiling until its upwards velocity runs out – the physics engine’s default behavior will be to stop the character when it hits the ceiling, reset the vertical velocity, and let gravity act on it, instantly pulling it downwards.
Or let’s consider a very simple, very basic yet essential maneuver: landing.
Have you ever seen a platformer player character bounce off of the ground when it lands? I haven’t. It makes for bad gameplay. Again, the “no jumping while in air” issue comes into play here.
Unfortunately, with physics this bouncing behavior is pretty much guaranteed. And it is difficult to circumvent: you have to determine that you’ve actually landed, and then you have to reset the velocities. The difficulty lies not in writing this code, but considering the various circumstances where this ideal scenario breaks. Landing on a moving platform, for example. Or disregarding pickup items because you don’t actually land on them.
Do you want the player to be sliding a little when changing movement direction? Then physics are a fine helper. If not, again you have to write code to force this behavior and consider circumstances where it doesn’t apply. Like for example when you do want to allow the player to change movement in mid-air but not abruptly like on the floor.
This list goes on and on and on …
Is it too early or too late?
Whenever you write custom code to circumvent physics engine behavior, you not only have to consider when you perform this code in relation to other characters. You also must know when to apply this to the physics body. You always have two choices: before or after the world step.
Which one you use normally doesn’t make any difference. But it can lead to subtle issues like the position of the player following the position of the moving platform with a 1-frame delay. Or it could have your character jitter on the floor, perhaps only after falling from a high ledge.
Normally you will want to feed the physics engine with your custom positions and velocities before doing the world step. But when you use other physics bodies’ positions and velocities in your calculations, they again may be one frame off.
In the worst case you may need to apply changes before the world step, and then verify positions and velocities for plausibility (or simply cap them) after the physics simulation and before the rendering.
Summary: physics engines vs platformers
Physics are simple enough to get you going, but you quickly get to the point where the physics engine stops being useful and only gets in the way. Depending on what game you are developing, you might get away with it.
For a really well done platformer, a physics engine is out of the question. You’d be too busy to fight it so that the time and effort it takes to create custom platformer collision routines that you’ll actually be able to debug is the preferable option.
To this end we’re currently in the process of removing and replacing physics engine code and behavior from Super Stick Spy step by step. Eventually we’ll have an implementation of platformer movement & collision behavior as explained in this great article and others.
Yet, since we already have the contour tracing code in, we can still use the physics engine for visual effects and dynamic bodies whose movement doesn’t need to adhere to platformer standards (ie items, physics puzzles).
|Follow @gaminghorror||Follow @kobold2d|