- Home /
Any reason why OnControllerColliderHit has a NaN normal?
I have a small MonoBehaviour script I attach to a game object in the editor, and the game object also has a CharacterController component attached to it. My question is, in my game, I (rarely) get into a situation where the ControllerColliderHit object passed to my OnControllerColliderHit function has a normal with NaN values. Can anybody think of a reason why this would happen? The rest of my source is pretty lengthy so I won't ask anybody to dig through it, but I use both Move() and transform.position to move the object around.
Here's the small component I use:
using UnityEngine;
public delegate void CollisionEventHandler(ControllerColliderHit hit);
public class CollisionDetector : MonoBehaviour {
public CollisionEventHandler OnCollision;
public void OnControllerColliderHit(ControllerColliderHit hit)
{
if (float.IsNaN(hit.normal.x))
Debug.Log("Collision detector NaN normal");
if (OnCollision != null)
OnCollision(hit);
}
}
Try printing hit.gameObject.name
(check for gameObject existing first?) $$anonymous$$y guess is that you're "hitting" something that doesn't have a normal (a size 0 collider?)
I only have 2 objects in the scene, a game object with a character controller and a camera attached to it, and then a gigantic plane (1000x1000).
I'm running a client/server simulation here, so could it be that the server is sending a state that positions the controller in an intersecting position with the plane? I did a trace on the collider object and it says it's colliding with 'Plane,' which is my plane, with NaN in all the hit.normal values (x,y,z).
The funny thing is it doesn't actually affect anything. If I just check for a NaN normal in the CollisionDetector object and bail out if it's NaN, the simulation runs along just fine, so it only happens every once in a while. I just run around in circles and eventually it pops up.
The NaN normal also never crops up server-side, just on the client.
Ah...so being moved by the network is probably all the odd results.
I'd guess it's not considered a problem, since most people put if(NetworkView.is$$anonymous$$ine)
in front of all logic checks, anyway. The idea is that the "real" server-side object will hit and RPC the results to me. The client shouldn't be using laggy data to get inconsitant results.
Answer by aldonaletto · Mar 12, 2012 at 01:35 PM
I have used OnControllerColliderHit a lot, and never observed this issue. Maybe the transform.position changes are fooling the collision system and producing this error - a Character Controller is supposed to be moved only with Move and SimpleMove.
You could try to replace any transform.position assignment like this:
transform.position = newPosition;
by a Move equivalent:
character.Move(newPosition-transform.position);
You could also try to do all Move or transform changes in FixedUpdate (the CharacterController belongs to the physics engine like the rigidbodies).
The NaN normal occurs either way, if I set the position manually or use $$anonymous$$ove. Placing the $$anonymous$$ove in a FixedUpdate isn't an option on account of the choppy movement it produces. I'm not using any of the actual unity physics tools other than the character controller and move. I apply my own forces and keep track of my own velocity, and after all my calculations I just toss my calculated velocity into the $$anonymous$$ove command.
Answer by Smooth P · Dec 22, 2013 at 06:52 PM
I'm in an extremely similar situation and started getting this in Unity 4.3, leading to hard crashes / lockups. It took me literally days to diagnose, all I knew was that my state data was getting corrupted, and I poured through and logged every piece of physics related floating point math in my codebase, thinking I must have played a bit fast and loose somewhere and forgot that floats aren't reals, or that maybe there was a corner case networking bug, but lo and behold, I find the occasional though incredibly rare NaN filled normal in ControllerColliderHitS.
Why having NaN values in a CC Move would cause a hard crash is beyond me (it should certainly fail more gracefully than that), but a hit normal should quite obviously NEVER NEVER NEVER NEVER NEVER come back NaN. That's simply not valid and breaks the contract of the API.
For now I guess the solution is to assume Unity physics are even more broken than usual and manually guard against NaN normals.