Character controller from scratch

Post Reply
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Character controller from scratch

Post by N_K »

Hello all.

I'm making a simple game, which requires only a simple character controller, but I was unable to come up with anything usefull. First, I gave the built-in kinematic character controller a try, but, just like everyone else, I found out that it's broken right now, and there's no way to make it behave like it should without making serious modifications to it.

Then, I went the dynamic approach: make the character shape, limit the angular factor, then move it around by applying forces at the desired direction. It didn't work, it was "too dynamic", it started to move on its own even on the slightest slope (just like all dynamic objects supposed to behave). I even posted a question here about how to prevent this, but got no answer.

Then, I thought I'll flag the player object as a kinematic object. I found some code in this forum about how to move kinematic objects, so moving the object itself wasn't hard. But it didn't collide with anything, even if the Bullet manual says that kinematic objects can interact with other objects, and affected by collision detection. And I had no idea how to keep it on the ground. Normally, I'd use raycasting to test if the object is on the ground, but I found nothing about this in the manual.

And here I am now, completely lost. I have no idea how to implement a proper character controller from the ground up. Could anybody who made a custom controller give me some clues about what to do/how to do? Your help would be greatly appreciated.

(Also, I took a look at the source of GameKit (since it has a proper character controller), and surprisingly, it seems that it uses the built-in kinematic character controller, but I was unable to figure out how does it works exactly, since it's a quite complex framework with complex code structure...)
Mr. Wonko
Posts: 4
Joined: Tue Mar 09, 2010 3:35 pm

Re: Character controller from scratch

Post by Mr. Wonko »

I'd like to know this as well - what do I need to know to implement a custom character controller?

I know how it works on a high level - inherit from btActionInterface so you have a callback that's called every frame, then manually do collision detection with a dummy shape and handle movement. But how do I do collision detection? And how could I handle special cases such as standing on moving statics (e.g. animated platforms)?

--edit--
If I understand this correctly, I need: A collision test to see if the player is currently stuck in something (because something moved into him, for example), reacting to it as appropriate (e.g. being pushed by animated statics, but reflecting dynamic rigid bodies), a sweep test to see if/how far you can move in the desired direction (handling the special case of sliding along a wall somehow) and a contact test to see if the player is on the floor and hence allowed to jump. Anything I'm missing?
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Re: Character controller from scratch

Post by N_K »

Okay, I came up with a (rather crude) sollution for a dynamic character controller: I created a capsule collision shape for my player. On input, I modify the linear velocity of the player. And before each step, I reset the linear velocity to zero, so the player is not sliding down on slopes/terrain.

Here's some pseudocode (mind that my character don't move diagonally, hence the rudimentary controll):

Code: Select all

void GetInput()
{
  if(IsKeyDown(UPARROW)) { playerBody->setLinearVelocity(btVector3(0, 0, -4)); }
  else if(IsKeyDown(DOWNARROW)) { playerBody->setLinearVelocity(btVector3(0, 0, 4)); }
  else if(IsKeyDown(LEFTARROW)) { playerBody->setLinearVelocity(btVector3(-4, 0, 0)); }
  else if(IsKeyDown(RIGHTARROW)) { playerBody->setLinearVelocity(btVector3(4, 0, 0)); }
}

void UpdateGameState()
{
  [...] //The 3D engine's timing and drawing functions

  playerBody->setLinearVelocity(btVector3(0, 0, 0));
  GetInput();

  pWorld->stepSimulation( [...] );
}
(Feel free to laugh at it, but I hope you get the basic idea... :) )

Now, my only concern about this is that, obviously, the gravity works strangely on this object. As long as I keep moving the character, it will climb stairs/slopse, but will not fall, it keeps moving at the last vertical position, and after the input stops, it will return to the floor extremely slowly (a behaviour I don't understand, since I set the linear velocity to zero when there's no input).

So my questions are:
1, Do you know a sollution to this gravity-related problem?
2, Does it worth to keep on playing around with this controller, or is it fundamentally broken, and I'd better to forget about it?

Thanks in advance.
Mr. Wonko
Posts: 4
Joined: Tue Mar 09, 2010 3:35 pm

Re: Character controller from scratch

Post by Mr. Wonko »

N_K wrote:1, Do you know a sollution to this gravity-related problem?
I suppose that even though you set the velocity to 0, for one tick gravity can affect it, increasing the speed slightly, making it move down a little.

To make gravity work normally you could set the velocity to (0, oldYVelocity, 0) instead of (0, 0, 0), keeping the vertical velocity.
N_K wrote:2, Does it worth to keep on playing around with this controller, or is it fundamentally broken, and I'd better to forget about it?
It's not fundamentally broken, but the question of dynamic (i.e. constrained rigid body) vs. kinematic controller (i.e. self-written physics) remains.

The problem is that characters are not rigid bodies, and as such approximating them as one is hard. For example, you don't want a character to be able to fall over. You don't want him to slide down slopes. (And I suppose as with the gravity this still happens in your case, if only slightly.) You want to be able to ascend stairs. A Rigid Body doesn't work like that, usually, so you have to constrain it a lot.

If you write the physics yourself, you have greater control at the cost of more work, since you have to code all interactions, like gravity, not moving through walls, pushing dynamic objects etc. yourself.

Maybe a dynamic controller is fine for you, maybe it's not - I guess it depends on what you need and how much work you're willing to do. As for me, I'm going to write a kinematic character controller, but it's pretty complex and I haven't really started yet.

I'm sure you can find out more about dynamic vs. kinematic character controllers by searching the internet, for example [ulr=http://www.digitalrune.com/Support/Blog ... llers.aspx]this[/url].
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Re: Character controller from scratch

Post by N_K »

Thanks for your reply.

I started experimenting again, and I'll consider your tips.
Mr. Wonko wrote:For example, you don't want a character to be able to fall over.
How can it fall over if the angular factor has been set to zero? It never happened to me so far.
Mr. Wonko wrote:You don't want him to slide down slopes. (And I suppose as with the gravity this still happens in your case, if only slightly.)
I managed to overcome this in a quite hacky way again. I've manipulated the friction of the player's body, until I found out a value which was enough to keep it from sliding down on slopes below a certain angle. I made a test level with a slope. I placed the player there, and made my 3D engine to monitor its position. Then I left the simulation running overnight, and 10 hours later, the player was exactly at the same position as it was when I left it.

Anyway, I still feel a bit strange for using hilarious tricks for this. But some "big" physics engines (Havok, for example) have dynamic character controllers by default. How do they overcome this problem? Setting friction seems logical, since this is (more or less) how it works in real life, but since I (obviously) don't have access to the Havok source code, I have no idea how is this done. Do you (or anybody else) know anything about this?
Mr. Wonko
Posts: 4
Joined: Tue Mar 09, 2010 3:35 pm

Re: Character controller from scratch

Post by Mr. Wonko »

N_K wrote:
Mr. Wonko wrote:For example, you don't want a character to be able to fall over.
How can it fall over if the angular factor has been set to zero? It never happened to me so far.
Yeah, that's what I meant by constraining the rigid body. I was just talking about a rigid body's default behaviour.
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Re: Character controller from scratch

Post by N_K »

Oh, okay. I didn't get it at first. Sorry.

And you're right, on the long run, a kinematic controller would be a more suitable approach for the kind of game I'm developing, with all those slopes and terrains. But I remember when I was experimenting with a kinematic body, I ran into some weird problems. First, the movement speed of the object was dependent on the framerate. No matter how fast it gone when the FPS was around 150, when I turned on VSync (which also limits the FPS to the monitor's refresh rate, 60 in my case, but later, I'd like to lock the framerate to 60 FPS anyway), it barely moved. Second, it acted like a bulldozer: for example, if I pushed a cube against the wall, the character easily pushed it out of the level, through the world geometry. Have you encountered these problems during your experiment with your custom kinematic controller?
mdias
Posts: 12
Joined: Thu Jun 28, 2012 2:21 pm

Re: Character controller from scratch

Post by mdias »

If properly implemented, a dynamic body doesn't seem like a bad idea at all to me.

I am currently developing a project (2D platformer) and I'm using a dynamic body because of all the benefits that come with it such as walking on moving platforms, mostly automatic collision handling and so on.

Here's a video I just did showing how it's working so far:
http://www.youtube.com/watch?v=qXFNQIa8QQs

The player consists of a btMultiSphereShape (btCapsuleShape has some problems with margins right now on bullet) and a cylinder connected by a ball constraint. Make the cylinder rotate and you have a walking character. Of corse for this to work you need to have friction on the cylinder and the surface it's on, which is nice because it will prevent your character from sliding on hills.
Want a slippery (such as snow) surface? Just reduce it's friction :)

[edit] the only problem I've had up until now is the impulse the character receives when landing from high heights. Even with cylinder's restitution being zero, sometimes it bounces a bit. This won't be a problem for me, but for those of you who sees it as such, I believe it could be fixable by interveining on the cylinder's collision handling process for this specific case while keeping all the other advantages of using a dynamic body.
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Re: Character controller from scratch

Post by N_K »

Thanks for your reply.

Using a "rolling" dynamic character controller seems to be the universal method when doing platformers (I've read about this in many forums/blogs), but the problem is that my character moves in four directions versus the two used in platformers. So I would either need a ball as the "wheel", or a complex "driveline" with multiple wheels, suspension, and things like that.

In a few hours, I got pretty nice results with the dynamic capsule method, now it's affected by gravity (more or less), it doesn't move on it's own, so it's nearly perfect for my game (a remake of a 2D RPG).

The only remaining issues I have right now is:

1, When the player moves up a slope, it will bounce a bit when the movement stops. This is obviously caused by the small contact point of the capsule shape, and this would be indeed solved by the "wheel" method.

2, The actually serious problem is that sometimes the player can stick to the wall, even if I make the character's Y velocity to be affected by the gravity in each simulation step (and it works, because it can ascend slopes and stairs without any problem). I have a set of stairs, leading to a platform along a wall. When I move off the platform, and press the forward button before the player lands (and holding the button down), the character will stick to the wall until the forward button has been released. And this only happens on the Z axis.

(Oh well, I think this post doesn't make much sense right now, it's time to sleep. :D)

If I won't be able to solve this tomorrow, I'll post the actual code (and possibly the application itself) to show you what I am talking about.

Thank you all for your help, and it's nice to see that there are still some people around here who are willing to help a beginner.
N_K
Posts: 14
Joined: Mon Jun 04, 2012 11:40 pm

Re: Character controller from scratch

Post by N_K »

Alright, I was unable to come up with anything useful regardin the wall-climb problem. And I can't post the code, since it's extremely complicated right now, but I'll try to explain how it works.

The player body is moved by linear velocity on the X and Z axis. The Y axis movement is supposed to be handled by gravity. Right now, I reset the player's position before stepping the simulation like this:

Code: Select all

PlayerBody->setLinearVelocity(btVector3(0.0f, PlayerBody->getLinearVelocity().y(), 0.0f));
This will prevent sliding on the X and Z axis, and (somehow) automatically make the Y position correspond to gravity.

Then, the player movement code looks like this:

Code: Select all

if(isKeyDown(UPARROW)) { PlayerBody->setLinearVelocity(btVector3(0.0f, PlayerBody->getLinearVelocity().y(), -5.0f)); }
And here is the problem. The Y axis is update by getting the previous Y position, but when I keep holding this key down, the object doesn't seems to be affected by gravity (that's why it can stick to the wall). When I change the Y value to:

Code: Select all

DynamicsWorld->getGravity().y()
The player won't move at all, and I'm not sure why.

How can I make the Y value of the linear velocity to work independently from user input, and be controlled by the gravity instead?
mdias
Posts: 12
Joined: Thu Jun 28, 2012 2:21 pm

Re: Character controller from scratch

Post by mdias »

Perhaps you have some friction going on between the player and the wall?
Or maybe the force you're pressing the wall makes it somehow penetrate it in a way that the generated impulses will make your Y velocity zero...

I still believe you'd be better of using a sphere as a wheel below the player, else you'll be coding extra stuff to make the player not change direction while in mid-air etc.
Post Reply