• entries
743
1924
• views
581594

# Back to CharacterControllers

923 views

Dumped the 2D game. It was going okay technically but just wasn't fun to play so had to make the decision to scrap it.

Back determined to write a 3D platform game again, so back to grappling with a 3D character controller. Learned a few tricks in the 2D game to do with raycasting to find the floor for handling slopes, hopefully will make this more successful than last time. CC's are a nightmare to get right.

At least I made a reasonable model as part of the 2D game that I can use in this one when I get to that point.

Have written a simple level editor that should be able to be expanded as this develops.

But until I can get the capsule behaving correctly with slopes and so on, no progress in any other area.

I have my own GJK implementation working fine as is - the character can be moved around with WASD and R/F to rise/fall and collides and responds correctly to the level geometry, and it is set up to be able to do raycasts but I've had a few dummy runs of trying to get slope behaviour working well with gravity and so far it has all ended in tears.

The key seems to be to only apply gravity when you are not grounded, but the distance to the ground is different for a capsule depending on the angle of the slope, which makes it tricky. I also want to have a maximum climbable slope angle and have steeper slopes block the character but still allow sliding. Its a nightmare. Nobody understands my pain.

I will battle on. Victory or death.

CC's are a nightmare to get right.

...

Nobody understands my pain.

I understand the pain, believe me !

Character controller as mix of user controlled and physics controlled, is really hard. I'm still not satisfied with my character controller yet, thought here are some ideas:

Ground detection: I use two flags for ground contact, one for even frames and one for uneven frames. I only take away user control, if both flags are not set, that is, if the character don't have contact in two consecutive frames.

Raytests: Raytests are really useful, but the question is how do you use the result ?

If you try to teleport the character to the target position after a successful raytest, you could end with an unwanted intersection. One solution would be to either use forces to move the character into the desired direction and let the physics engine handle all the stuff, including walking up a slope, or you can do a collision test before teleportion. The first approach would result in some messy force stuff (keep forces so that velocity is constant regardless of slope), the latter stuff needs more collision test (if first collision test failes, move it up/down and test again, binary search)

Cheers for the post, Ashaman.

I'm not actually using a physics engine here, this is all hand rolled so I can move my controller around as I see fit with a bit more freedom than normal. I certainly don't have to mess about with forces here, thankfully.

I had some success in my 2D game by having the controller be a capsule balanced on a ray, with the ray being long enough that the capsule would never intersect the slopes it was allowed to walk up, and just locking the capsule to a predetermined height above the surface when the ray distance was <= a given value.

But it certainly wasn't perfect and first half-hearted attempts to do the same in 3D have not ended well. I will keep trying and post any progress here.

One of the biggest problems I've found is slopes that are too steep - making the character stop at the bottom and slide as if it was a vertical wall, but slide down if falling onto the slope from above. I "solved" this in the past with an invisible shape at the bottom of slopes that only blocked you if a) you were grounded and b) you were moving towards the slope, but I'm determined to find a generic solution that doesn't require fake geometry this time.

Must be possible. MUST be possible!

[EDIT] Your idea about using consecutive frames like that is interesting, I can see how that might work well for reducing some jitter.

Okay, time to try a different approach. Trying and failing to get perfect movement from the physics shape and the more I try to correct out every tiny little jitter, the more and more complex the code is getting. Its horrible.

But if I accept the jitter, it is actually really simple:

void Pc::update(Physics &physics, float delta)
{
Vec3 vel = getVelocity(camera) * (4 * delta);
Vec3 pos = body->position();

HitInfo floor = findFloor(pos + vel, body, physics);
Matrix floorMatrix = identityMatrix();

if(floor.valid())
{
floorMatrix = rotationToMatrix(Vec3(0, 1, 0), floor.normal);
vel = transformNormal(vel, floorMatrix);
}
else
{
if(!getAsyncKeyState(VK_SPACE)) vel.y -= 8 * delta;
}

vel += transformNormal(physics.getSeparationVector(body, pos, vel), floorMatrix);

body->setPosition(pos + vel);
}



That's the whole update for the player. findFloor does one ray cast and getSeparationVector uses the GJK to get the MSV from any intersecting shapes.

So... what I think I might try instead is to accept the jitter on the invisible physics shape but remove the jitter instead from the actual rendered object. If the object is grounded, I can re-raycast to find the floor, then position the model relative to that point. That should remove any of the vertical jitter. And if I only update the scene object's position after it crosses a certain small threshold away from its previous position, smaller than a move step but larger than the jittering, that should remove the rest.

I think. Going to give it a try, which will involve implementing scene objects as at the moment I'm just debug-rendering the physics objects.

I may still need invisible blocker shapes at the base of steep slopes, as the jitter around those is probably too high to just ignore when rendering the object, but that isn't the end of the world. I noticed from looking at the docs for PhysX that it does something similar so as long as I can auto-generate these shapes and I don't have to create them in the editor, who cares?