Search Unity

Spline Guided Rigidbody Going Upside Down

Discussion in 'Physics' started by DanMarionette, May 23, 2016.

  1. DanMarionette

    DanMarionette

    Joined:
    Jan 16, 2011
    Posts:
    27
    Hello,

    I have, for a long time, been trying to find a solution to the game I'm trying to make. In my game the player controls a handcart that travels on railway tracks and can jump over obstacles. If the obstacle is ramp or sometimes if the player doesn't make the jump in time, then I want the handcart to reaction to be physics driven, whilst still sticking to the spline that defines the track. My current solution works fantastic in almost all cases.
    When the player accelerates I apply a force in the handcarts forward direction, then in LateUpdate I set the local x velocity to 0 to stop it from drifting sideways off the track. I then take the closest position to the handcart of spline and set the handcarts x and z position to match. That way the cart is locked to the spline, but I retain the y axis for the physics to control, for jumping, falling etc.
    I then take the orientation of the spline at the same position and take the euler y axis to apply it to the handcarts transform rotation whilst once keeping the physics calculated x and z.
    This all works very well and the handcart can travel around a spline at incredible speed whilst jumping either via the players input or going over a ramp. The problem however (some of you out there may have already guessed) is that the handcart cannot go upside down. The moment it rotates beyond 90 degrees on x in either direction it starts to dance around on its nose, constantly fighting with something.
    I say something because this is the bit I just cannot figure out. I have tried many different methods of applying the rotation and they either give the same result or a poorer version. I am hoping though that I have not tried all things and that there is a solution to my problem.

    Code (CSharp):
    1. protected void LateUpdate()
    2.         {
    3.             if (Spline && Spline.IsInitialized && _transform)
    4.             {
    5.                 var transformPosition = Spline.transform.InverseTransformPoint(_transform.position);
    6.                 var splineTf = Spline.GetNearestPointTF(transformPosition);
    7.  
    8.                 ConstrainRotation(splineTf);
    9.                 ConstrainPosition(splineTf);
    10.             }
    11.         }
    12.  
    13.         private void ConstrainPosition(float splineTf)
    14.         {
    15.             var velocity = _transform.InverseTransformDirection(_rigidbody.velocity);
    16.             velocity.x = 0;
    17.             _rigidbody.velocity = _transform.TransformDirection(velocity);
    18.  
    19.             var splinePosition = Spline.transform.TransformPoint(Spline.InterpolateFast(splineTf));
    20.             splinePosition.y = _transform.position.y;
    21.             _transform.position = splinePosition;
    22.         }
    23.  
    24.         private void ConstrainRotation(float splineTf)
    25.         {
    26.             var newRotation = Spline.GetOrientationFast(splineTf).eulerAngles;
    27.             newRotation.x = _rigidbody.rotation.eulerAngles.x;
    28.             newRotation.z = _rigidbody.rotation.eulerAngles.z;
    29.  
    30.             _rigidbody.rotation = Quaternion.Euler(newRotation);
    31.         }


    I know my case may be a bit more specific but I have read a lot of posts and answers, trying to fix this issue and I have seen there seems to be an issue manipulating the euler angles at the 90 270 degree points. I wanted to explain what I'm trying to achieve to give you the background, but I think the issue lies at the manipulation of the rotation via euler angles.

    Has anyone come across this issue before and found a solution? Any ideas of anything else you think I could try?