- In running/jumping games, player movement is paramount. It takes forever to nail the right feeling.
- Each game is a unique snowflake. You will not find an article explaining how to design the controls for your specific game. You're flying blind.
That said, each game offers a few transferrable bits of wisdom. Here's my story.
Make a character
You're a programmer, but one time you were able to suppress the gag reflex while using GIMP, so you're pretty much an artist too. You can draw a player character.
That's certainly... a drawing. So the player is an anthropomorphized cylinder? Well, we've seen worse.
If this character has any flaw, it's that he's too exciting and interesting. Can you make him a little more boring and generic? What if you use MakeHuman? It literally generates human characters from a template.
Much better. But there's just one problem: this is a first-person game, so when players look down, they can see their own nose:
Also, the "pectoral musculature" slider is a tad high, and players are getting confused about their gender.
You end up switching to a female character. Because why not?
Now for the nose problem. You can't remove the entire head, because a headless shadow might be somewhat disconcerting. What if you just remove the face?
[size=2]Perfect.
(Eventually you revamp the model, hire an animator, and use separate models, one sans head, for the first-person view and shadow renderer. But none of that is entertaining.)
Make it move
You're using a great physics engine (seriously, it's quite good) that comes with a simple character controller. It looks like this:
The character is a cylinder floating above the ground, supported by a single raycast. This way, the cylinder can clear a small obstacle, and once the raycast hits it, the whole apparatus jumps on top.
Since the game world is made of voxels, you quickly run into this problem:
Tons of players get stuck this way in your first alpha release. Rather than spend time on an elegant solution, you brute-force it:
Despite this, people still get stuck. You resort to a collision handler that actually pushes the character away from anything that could cause problems. You also interpolate the vertical position to smooth out the camera when traversing uneven voxels:
Make it unrealistic
In an attempt to model reality accurately, the game has no air control at this point. When you originally made this decision, you somehow forgot that the game is about an imaginary cube world.
Thankfully, after listening to player feedback, you have a change of heart. In the real world, traceurs have many control dimensions (namely, their muscles) that enable precise jumps. Video games have exactly one button. Air control is only fair.
Make it fun
Since parkour is about momentum, you want the character to take several seconds to reach max speed. Which is fine, except that low acceleration makes small adjustments difficult. The first step takes forever, and the character feels like a semi truck.
Your solution uses different accelerations depending on the current speed. The final speed curve looks like this:
This solves half the problem, but players can still use the mouse to quickly whip the camera around 90+ degrees, which resets their speed back to zero.
You experiment with a few hacks, but eventually settle on a solution using the dot product. It's basically a measure of the angle between two vectors multiplied by their magnitude. (Here's a quick interactive demo.)
You use a dot product to find out how much side-to-side momentum the character has. If they're facing perpendicular to the direction of their momentum, the dot product will be large. You use that to increase the acceleration. Long story short, turning no longer burns momentum.
Make it slippery
There are other ways to lose momentum, like running into a brick wall. You try to mitigate this with low friction physics materials, but angling yourself into a wall will always slow you down:
You are inspired by a blog post by Mike Bithell on this topic. You use three raycasts and some cross product magic to figure out a velocity that will slide along the wall.
Later on, you discover another annoyance. Your wonderful voxel engine sometimes helpfully constructs voxels like this:
There's a seam between the two adjacent blocks due to floating point error. When the character moves flush with the wall and tries to jump upward, it hits the seam and immediately stops.
The solution is brain-dead simple: change the cylinder to a capsule. Yes, it really does take you 4 years to figure this out.
Make it forgiving
At first, players just don't understand the movement mechanics. They think they can't get from point A to point B, until you tap them on the shoulder and explain they have to do XYZ. You suspect this is because your tutorial is actually a placebo at this point.
Eventually, the tutorial gets pretty good. Everyone understands the movement capabilities, and they can figure out which moves to use. But now they have a new problem: they fail in the twitchy execution and timing details of their plans.
The worst culprit is a single infamous jump in the tutorial. It tries to teach players how to grab ledges because it's too long to cross with a normal jump.
Players fail two or three times before you tell them to "button-mash", which helps them nail the timing through sheer brute-force. Interestingly, as soon as they make this one jump, they have no trouble completing future jumps without button-mashing. For a while, you arrogantly conclude that people are just stupid.
Part of the problem is still the tutorial: you ask players to make a leap of faith and perform a move they've never seen before. They have no idea what the character will do or how long it will take. So you add another, earlier tutorial that lets players try out the ledge grab in a safe space.
But the frustration of perfect timing remains. The solution is two-fold:- Let players jump for a split second after they walk off an edge.
- Let them hold buttons instead of tapping at the right moment.
To the surprise of no one but you, this makes the game a lot less frustrating and a lot more fun.
Make it look good
Over the course of development, you stumble on a few animation tricks. With enough nifty procedural animation, maybe people won't notice your shoddy weight painting and texture work!- Attach the camera position to the character's head bone, but use a separate root bone to control camera rotation. This eliminates weird rotations when blending between animations.
- Speaking of which, use a quadratic curve to blend between animations rather than straight linear.
- Also, don't use linear matrix interpolation. Instead use quaternion interpolation.
- Remember the dot product from earlier, for calculating side-to-side momentum? Use that to make the character and camera lean when turning at speed.
- Run the character bone transforms through filters for nice effects like tilting the character's head when looking up and down.
- Plant the character's feet and play a little foot-shuffling animation when turning in place.
(For a much more eloquent and in-depth look at procedural animation, check out David Rosen's GDC talk.)
Conclusion
Budget an extraordinary amount of time for your character controller. Make it special and unique. And if you're me, prepare to be wrong most of the time.
Lemma is set to release in May. The entire game engine is on GitHub. If you enjoyed this article, try these:- The Poor Man's Postmortem (coming soon!)
- The Poor Man's Voxel Engine
- The Poor Man's Dialogue Tree
- The Poor Man's Gameplay Analytics
Thanks for reading!
Mirrored on my blog
- The Poor Man's Postmortem (coming soon!)
- Attach the camera position to the character's head bone, but use a separate root bone to control camera rotation. This eliminates weird rotations when blending between animations.
- Let players jump for a split second after they walk off an edge.
Let's say that, like so many of us, you want to make a surreal voxel-based first-person parkour game. You're trying to figure out a production schedule. What will take the longest? Graphics? Sound? Level design? I bet it will be the character controller. And I bet it will take 4 1/2 years. Why?
Previous Entry
Screenshot Saturday 213
Next Entry
PR-o-matic
Comments
April 07, 2015 07:57 AM
I agree with aardvajk, you two should get collaborating immediately :) Also, can't wait for this on steam. I keep talking it up to my IRL friends. Do you have a price point for NA market yet?
April 10, 2015 05:04 PM
Thanks! Not 100% sure on the price, but leaning towards $15USD with a 10% launch discount.
April 10, 2015 11:32 PM
[quote name="Aardvajk" timestamp="1428393441"]Maybe one of us should write an article.[/quote]I'm sure such an article would be very popular, both of you regularly have interesting and well-written normal entries, so we'd love to see any articles from either or both of you! :)
April 11, 2015 06:29 AM
Ill try to make a start on an article about how I implemented mine. It's from scratch, no libraries apart from D3DX rather than using a physics engine so might be an interesting thing to have on the site.
April 12, 2015 10:06 AM
April 13, 2015 01:37 PM
Very encouraging to read this. My character controller sapped my life force for a good 1/3. I hope I can remember those tricks.
April 13, 2015 03:13 PM
Advertisement
Latest Entries
The Poor Man's Netcode
8667 views
DECEIVER - announce trailer!
2413 views
The Poor Man's 3D Camera
5091 views
Thirteen Years of Bad Game Code
5642 views
Enlisting IBM Watson as a voice actor
3279 views
The Poor Man's Threading Architecture
5958 views
Ludum Dare 34 Postmortem
4184 views
One Weird Trick to Write Better Code
8378 views
The Poor Man's Postmortem - Lemma
8031 views
It's done!
4976 views
Advertisement
Another great write up, thanks. I share your pain and spent similar time getting a capsule based character controller balanced on a ray cast working. It is one of the most tricky things in all of game development to my mind, not least because it is not a subject with much in the way of online resources available. Maybe one of us should write an article.