Hello, I’m using a Character Controller on my third-person character, which works pretty well, except in one case: When the character steps just beyond the edge of a cliff but the base of the capsule-shaped character controller still touches the edge of the cliff.
The result is the character magically floats in the air instead of falling. Is there a way of “forcing the character down” so that it’ll slide and fall even if a tiny part of its controller’s base is in contact with something?
I’m thinking it happens because CharacterController is using the CollisionFlags returned by the Move function to determine if it ‘isGrounded’. Since the edge is touching the bottom part of the capsule, CollisionFlags.Below is true and therefore we are grounded.
Anyone been able to solve this?
Well I haven't. And yes, I also think it happens because the tiniest part of the character controller is still in contact with something...
I have a similar problem. My player model is wider than the other side, so the character controller radius is much bigger in one direction. So the character is always floating, if seen from side, on an edge or cliff. How can we overcome this problem?
Thanks for your inquiries, NervousNerve. It seems you put a lot of thoughts into this. How about this: When you detect the collision flags and find out that only an off-center bottom point is in contact with the ground, how about just firing a Physics.Ray down from the capsule's opposite side? That way, if you don't get any hit on a distance of let's say 50cm, then you'd know for sure that the player is not standing on a slope, but on an edge instead. Does that make sense?
The messy and dirty way I did something similar to this is that I made triggers of when they are at the edge. You can then AddForce, or MoveForward, or SetVelocity forward just a little bit, so that then the character controller does go off the cliff.
Again, it’s dirty but that’s what I’ve used. If there’s any other options I’d like to know as well.
If your character controller parent game object has children with colliders (primitive or mesh) they will cause problems with the character controller’s ability to handle collision. Try removing colliders from any children.
I spent an hour messing with slope, skin and step offset until I tried removing the collider from my head mesh then adjusting my body collider to also cover the head. Cleared my issue right up and I was able to put my slope, skin and step offsets back to realistic values without any issues. Makes calculating headshots a little more tricky, but I’ll probably just replace the character controller with a custom one eventually.
Add the following to your code:
// Making sure that when the player is not colliding with any object, he is suspended in air must handle aerial movement
bool m_IsColliding;
void OnCollisionStay () {
m_IsColliding = true;
}
void OnCollisionExit () {
m_IsColliding = false;
}
// Inside the Move function replace:
if (m_IsGrounded)
{
HandleGroundedMovement(crouch, jump);
}
else
{
HandleAirborneMovement();
}
// with:
if (m_IsGrounded) {
HandleGroundedMovement (crouch, jump);
}
else if (m_Animator.GetCurrentAnimatorStateInfo (0).IsName ("Grounded") && !m_IsGrounded && m_Animator.GetBool("OnGround") && m_IsColliding) {
m_IsGrounded = true;
}
else
{
HandleAirborneMovement();
}
// replace HandleGroundedMovement function with:
void HandleGroundedMovement(bool crouch, bool jump)
{
// check whether conditions are right to allow a jump:
if (jump && !crouch && m_Animator.GetBool("OnGround") )
{
// jump!
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.SetBool("OnGround", m_IsGrounded);
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
}
Hi, once I do the code changes according to your script, player just keep jumping forever, I guess there must be something wrong, somewhere. BTW, Im on Unity 5.1.2 using ethan controller. Regards,
// Somewhere in your update
if (_controller.isGrounded && IsOnTheEdge()) {
_controller.Move(transform.forward * 2f * Time.deltaTime);
}
...
// Function to check if the character is on the edge
private bool IsOnTheEdge() {
if (Physics.Raycast(transform.position, Vector3.down, out var hit)) {
return !hit.collider.isTrigger && Vector3.Distance(hit.point, transform.position) > 0.2f;
}
return true;
}
Well I haven't. And yes, I also think it happens because the tiniest part of the character controller is still in contact with something...
– SeithI have a similar problem. My player model is wider than the other side, so the character controller radius is much bigger in one direction. So the character is always floating, if seen from side, on an edge or cliff. How can we overcome this problem?
– msl_manniThanks for your inquiries, NervousNerve. It seems you put a lot of thoughts into this. How about this: When you detect the collision flags and find out that only an off-center bottom point is in contact with the ground, how about just firing a Physics.Ray down from the capsule's opposite side? That way, if you don't get any hit on a distance of let's say 50cm, then you'd know for sure that the player is not standing on a slope, but on an edge instead. Does that make sense?
– Seith