So i'm trying to build a character controller using no rigidbody, capsule collider or the default character controller. Instead i'm trying to catch collision events with a few CapsuleCasts.
I can jump, run around and not fall trough my terrain; which is all great. However i'm trying to run up an incline plane, the capsule cast does not register a hit until the center of the capsule collides with the plane.
I was going to post some code snippets, but a zipped up version of my project might be more helpful. http://defalcator.com/Raycast.zip (Ignore the filename)
Can anyone help me out as to why the collision isn't registered on time? I want to catch the collision when my player first steps on the slope so i can correct it and implement ground following...
Thanks
~Gabe
We’ve been having the same problem for a while now and finally found the solution. You must add the radius of the capsule to the sweep distance, since unity checks from the middle of your capsule to the end of a line, not the middle of the end capsule as I thought as well.
I hope this helped, as I know the frustration of not having reliable physics checks.
-Kristian BD
Check the y-coordinate of P1 and P2, if P1 is below P2 (lower altitude) Physics.CapsuleCast WILL work. If not, everything will go to hell.
http://forum.unity3d.com/threads/130169-Why-CaspsuleCast-is-buggy
I’d also like to keep a remnant of my old answer.
This is a very powerful bit of code (which I dub IterationArray):
var hit : RaycastHit;
var hit2 : RaycastHit;
if(Physics.Raycast(pos - Vector3.up*0.5,dir,hit,Mathf.Infinity,(1 << 0))
&& Physics.Raycast(pos - Vector3.up*0.5,-hit.normal,hit2,Mathf.Infinity, (1 << 0))
&& (hit.distance < radius + dist || hit2.distance < radius + dist))//find the normal below us and find how close it is
{
if(hit.distance > hit2.distance)
{
hit.distance = hit2.distance - radius;
}
else hit.distance -= radius;
}
Basically, what it’s saying is: find the nearest normal below you, then do a raycast along the opposite direction of that normal and find the closest distance. If either of those distances are within a suitable distance, then use that normal and DON’T spherecast because it will just waste CPU and give you a slightly less accurate normal. Furthermore, CapsuleCast/SphereCast are unreliable in that they will not return anything if they start “sweeping” from inside a mesh.
Usually, my collision codes look something like this
if(Physics.Check Capsule) //if there is something occupying the space, then do stuff, otherwise don't bother
{
if(IterationArray) //check if we are on a flat plane first
else if(Physics.SphereCast) //check for a contour or corner of a mesh
}
I think your problem might have to do with planar/non-closed collision meshes (floor). Testing against a closed cube gives very different results from a non-closed mesh. I don’t fully understand it, but there are many cases I’ve run into where the capsule will not register a collision with a mesh when that mesh already intersects the volume of the starting capsule. I find that when the starting capsule doesn’t instersect a mesh, it will always collide with it during the sweep, but if it does intersect it, it may not collide depending on the angles of the collider polygon and the sweep angle. (Sorry I don’t have a definitive answer.)
One possible solution is to do a Physics.CheckCapsule before you do the cast to see if you’re colliding with anything in the volume of the starting capsule. If you’re not, then go ahead and cast forward.