Search Unity

Align Ridigbody to slopes while moving forward

Discussion in 'Scripting' started by kai_226, Jan 12, 2018.

  1. kai_226

    kai_226

    Joined:
    Jul 6, 2017
    Posts:
    53
    Hello guys,

    I have a rocket that travels forwards very fast. I need the rocket to align with the slopes of the track below. Currently, I use this script:


    Code (CSharp):
    1. private void FixedUpdate()
    2. {
    3.     forwardRay.origin = forwardRayPos.position;
    4.     forwardRay.direction = forwardRayPos.forward;
    5.     // forwardRayPos is at the tip of the rocket's nose
    6.  
    7.     if (Physics.Raycast(forwardRay, out forwardRayHitInfo, .5f, (1 << LayerMask.NameToLayer("Track") | 1 << LayerMask.NameToLayer("Ship") | 1 << LayerMask.NameToLayer("Weapon") | 1 << LayerMask.NameToLayer("Obstacle"))))
    8.     {
    9.         DestroyOnCollision(forwardRayHitInfo.collider);
    10.     }
    11.  
    12.     groundRay.origin = transform.position;
    13.     groundRay.direction = -transform.up;
    14.  
    15.     if (Physics.Raycast(groundRay, out groundHitInfo, 3f, 1 << LayerMask.NameToLayer("Track")))
    16.     {
    17.         rBody.rotation = Quaternion.FromToRotation(transform.up, groundHitInfo.normal) * rBody.rotation;
    18.     }
    19.  
    20.     rBody.velocity = Vector3.zero;
    21.     rBody.AddRelativeForce(Vector3.forward * 4000f);
    22. }
    Basically I am using one ray that gets the normal of the track mesh below and then I rotate the RB of the rocket towards it. I then need to cancel the velocity and give the RB some forward force again, otherwise the rotation won't happen quick enough. First question: Is there a better way to adapt the vertical rotation of the rocket to the surface below?
    I fear this code is everything but clean, especially setting the velocity to zero and adding a force right away on every FixedUpdate.
    When following the rocket at the same speed, the forward movement of the rocket looks very jittery.

    Secondly, the Rocket should explode when hitting GameObjects with a certain layer. The code above works, but the Rocket penetrates the object way too far before actually exploding.
    Keep in mind, I also use OnCollisionEnter and have a BoxCollider as trigger.

    Any tips on how to improve this script?
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You could avoid bitshifting and using raw strings by defining class-level LayerMask variables which you assign in the inspector.

    Why are you adding a force to the rigidbody every FixedUpdate? Is it to preserve the existing speed of the rocket? Maybe try other ways to do that without destroying/resetting the velocity. One thing to try is using the result of "FromToRotation" to rotate the velocity vector the same amount (quaternion * vector3). Another option is to get the magnitude of the velocity, and set the velocity to the new forward direction * that magnitude, giving you the exact same speed, but in the new direction. This would be an explicit velocity set, not an additive force.
     
    kai_226 likes this.
  3. bbQsauce

    bbQsauce

    Joined:
    Jun 29, 2014
    Posts:
    53
    Try to set the collision detection of the rigidbody to Continuous
     
    kai_226 likes this.
  4. kai_226

    kai_226

    Joined:
    Jul 6, 2017
    Posts:
    53
    Hey, thanks for your reply's.

    Yes, I want the rocket to keep flying at the same speed.
    Can you give me a quick example of how to do it? I am always struggling a bit when it comes to rotations, to be honest.

    And yes, the collision detection is set to Continuous. I may add that the obstacles that could be hit are sometimes a bit thin. Like 1/8 of the thickness of the rocket.

    EDIT:
    I think I know what you meant, now. And it works like charm! I don't even need the forward ray any more for colission check! I did not include the nicer layer check yet, but here's the edited code:

    Code (CSharp):
    1. private void FixedUpdate()
    2. {
    3.     forwardRay.origin = forwardRayPos.position;
    4.     forwardRay.direction = forwardRayPos.forward;
    5.     /*
    6.     if (Physics.Raycast(forwardRay, out forwardRayHitInfo, .5f, (1 << LayerMask.NameToLayer("Track") | 1 << LayerMask.NameToLayer("Ship") | 1 << LayerMask.NameToLayer("Weapon") | 1 << LayerMask.NameToLayer("Obstacle"))))
    7.     {
    8.         DestroyOnCollision(forwardRayHitInfo.collider);
    9.     }
    10.     */
    11.     groundRay.origin = transform.position;
    12.     groundRay.direction = -transform.up;
    13.  
    14.     if (Physics.Raycast(groundRay, out groundHitInfo, 3f, 1 << LayerMask.NameToLayer("Track")))
    15.     {
    16.         rBody.rotation = Quaternion.FromToRotation(transform.up, groundHitInfo.normal) * rBody.rotation;
    17.     }
    18.  
    19.     rBody.velocity = rBody.rotation * Vector3.forward * 100f;
    20. }
    Of course I'll clean it up a bit now.
    Thanks alot to both of you! :)
     
    Last edited: Jan 13, 2018
    LiterallyJeff likes this.