For a while our player characters have been looking a bit, well, boring.
You know what they were really missing? Capes.
But how do you make a cape work in a pixel art game anyway?
Simulating Cloth
I am neither a physicist nor a mathematician, but in high school I read a paper about Hitman's then-revolutionary ragdoll physics, which used a lot of grown-up words: "Verlet Integration", "Constraint Solving", "Relaxation" - it just didn't let up.1
But! After several days of bashing away at a keyboard, by some miracle I actually had some 2D stick figures that crumpled to the floor kinda realistically. It was the coolest thing I'd ever built.
And now I'm gonna show you how to work miracles like that too, only better:
- You make a bunch of dots.
- Move those dots downwards. 2
Then we add the magic:
- You take your dots and define some "constraints", like:
- "No dot must be more than 5 pixels away from its original neighbours."
- "These 3 dots at the top must never move." 3
- Make your dots fall like before, skipping any dots that can't move.
- Check all those constraints; if any two dots are too far away from each other, pick 'em up & move them closer together again.
- Repeat step 3 another one or two times.
That's literally it! That's the whole miracle! That gets you cloth:
Rendering Cloth
Well, okay, sure: our cloth is just a set of dots connected via lines. Ideally it should look like some sort of solid-colour cape.
To convert it to a cape, I look at all the dots to find the 'edge' dots, which make a polygon, and I find the smallest box that contains that polygon:
Then I rasterize that polygon using the most naive approach imaginable:
I check every single pixel in that orange box above to see whether it's in the polygon - and if it is, I draw a teensy 1-pixel wide rectangle:
I think the proper solution would be to use a shader, so the graphics card can do that rasterization work. But that's a problem for future Caspar!
Tweaking Cloth
Now if you paid attention above, you might have noticed that the cape technically works. But it also snaps around a lot, especially when the player lands after a jump - which looks silly.
And this is where we get to the less-cool thing about verlet-based cloth simulation: it requires a bunch of tweaking to look good. 4
I apply air resistance, dampen the angular momentum, and push the cape in the opposite direction to player movement, which makes it snap and flop a bit less. And to stop the cape compressing to a thin line when the player runs, I move the cape's attachment hotspots in the player's running animation:
Playable web build
Oh yeah, the main character has a gun now. We might talk about that more some other time.
For now, a quick heads-up: press R to swap between your two guns, and right click to aim.
I think it was this paper?
It's been about 2 decades, so some of that era's memories have been supplanted by life-saving details like "keyboard shortcuts to make Jira not feel slow as molasses".
This is the bit where you actually do the "verlet integration". As is required for all things mathematics, Wikipedia makes it seem super scary... but the key part is literally just new_pos = current_pos + velocity_damped * dt + acceleration * dt * dt
, and saving the old position before you overwrite it.
Was that so hard, Wikipedians?!
Well, the 3 dots at the top must never be moved via the verlet-integration simulation.
You do move them separately, otherwise the cape would stay hanging in mid-air instead of following the player.
I did also experiment with a different simulation technique called XPBD, which is less tweak-intensive - but I didn't quite get it working right, and ultimately I think I got this verlet-integration approach to a good-enough point that I need to move on.