What is wrong with my Capsule cast?


Im trying to get a capsule cast working to iron out some problems with the raycast in my isGrounded method.

Im not really sure I’m doing it right, could anyone tell me where Im going wrong?


bool isGrounded (){

	bool foundHit;

	RaycastHit hit = new RaycastHit() ;

            //distance of points from centre of capsule.
	float distanceToPoints = capCol.height / 2 - capCol.radius;

            //Position of each end of capsule.
	Vector3 p1 = transform.position + capCol.center + Vector3.up * distanceToPoints;
	Vector3 p2 = transform.position + capCol.center - Vector3.up * distanceToPoints;

	float radius = capCol.radius * 0.95f;
	float castDistance = 0.1f;

	return foundHit = Physics.CapsuleCast (p1, p2, radius, Vector3.down, hit, castDistance);


Imagine the capsule as two spheres and a cylinder between them.

 /     \___Sphere2
  \___ _/
 |      |
 |  ___ |
 /     \___Sphere1

For the CapsuleCast function you need center points of these 2 spheres and a radius of any of the spheres.

//get the point which is located at 'capCol.radius' higher than transform's bottom
Vector3 centerOfSphere1 = transform.position + Vector3.up * capCol.radius;
//and get th point which is located at
// ('capCol.height'-'capCol.radius') higher than transform's bottom
Vector3 centerOfSphere2 = transform.position + Vector3.up * (capCol.height - capCol.radius);

That’s how you get positions. Don’t ever add floats to a vector, as you did, Unity won’t trigger an alarm and will give you some vector as a result but what the result it will be, nobody knows, because vectors don’t work like that. You have to add vectors to vectors, not floats.
To get some point position when you know another point (e.g. transform.position) you need to determine in which direction from the transform that point is located. Here we know that the spheres’ centers are up from the transform bottom point (transform.position), so we are taking transform.position, then add the direction straight up (Vector3.up), and multiply the direction with a distance float that we need our point to be from the origin. Take transform.position, push it up and specify what the range hight should be. transform.position + Vector3.up * calCol.radius , so Position plus direction multiplied by distance. Like that.
Ok. Next thing I need to tell you. When you cast a capsule for ground detection, you need to set the radius of the capsule you cast a bit less than actual character’s capsule. Why? Because Unity uses a special offset to detect collisions, when two colliders are penetrating into each other, Unity let them to do that until the penetration gets higher that this special offset. In that moment Unity detects a collision between these colliders. This offset is called ‘Physics.defaultContactOffset’ and it’s 0.01 by default.
So, if you don’t make the casted capsule radius lower by this offset, your character bottom could fall into the terrain for 0.01 units and your capsule won’t detect the ground because it will start detecting process while it’s already under ground.
So, I suggest you to call a cast method like this:

RaycastHit hit;
Physics.CapsuleCast (centerOfSphere1, centerOfSphere2, capCol.radius - Physics.defaultContactOffset, Vector3.down, hit, castDistance);
if (hit.transform //capsule detected collision with some transform
    && hit.transform != transform) //It's not the character himself was detected
        isGrounded = true;

Oh, and also, you need to set spheres’ centers higher by that contact offset as well.

Vector3 centerOfSphere1 = transform.position + Vector3.up * (capCol.radius + Physics.defaultContactOffset);
Vector3 centerOfSphere2 = transform.position + Vector3.up * (capCol.height - capCol.radius + Physics.defaultContactOffset);

Good luck with your project.