The Poor Man's Character Controller

Published April 06, 2015
Advertisement
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?

  • 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.
3qqRJqkl.jpg
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.
0uvQADll.png

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:
jsAgDvnl.png

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?

Z70Rhl.jpg

[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:
C3ZMMiOl.png
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:

RDdpOgXl.png

Tons of players get stuck this way in your first alpha release. Rather than spend time on an elegant solution, you brute-force it:
SuQjLaQl.png

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:
9c7IGmzl.png

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:
QorUs73l.png

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:

WideeyedAdolescentIndianhare.gif

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.

YoungKlutzyHalibut.gif

Later on, you discover another annoyance. Your wonderful voxel engine sometimes helpfully constructs voxels like this:
7CMrj0Sl.png

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.
T0wgMJ3l.png

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.


1aNvzAql.png

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

rJk4nhel.jpg

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:
Thanks for reading!

Mirrored on my blog
Previous Entry Screenshot Saturday 213
Next Entry PR-o-matic
23 likes 7 comments

Comments

Aardvajk

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.

April 07, 2015 07:57 AM
Burnt_Fyr

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
evanofsky

Thanks! Not 100% sure on the price, but leaning towards $15USD with a 10% launch discount.

April 10, 2015 11:32 PM
jbadams
[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
Aardvajk
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
Navyman

When I first saw the "no face" model I was in a bit of shock to read the whole post.

April 13, 2015 01:37 PM
Krohm

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
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement