Search Unity

I Lose Control Of My Rigidbody When Lerping My Speed

Discussion in 'Scripting' started by Hotpockets26, Apr 13, 2019.

  1. Hotpockets26

    Hotpockets26

    Joined:
    Dec 16, 2017
    Posts:
    32
    I'm trying to create a boost in speed and then the speed goes back to its original value using lerp, but the way I'm modifying my speed is somehow causing me to lose control of my character for a second once the speed starts to ramp back down. Could someone take a look at my code and tell me what I'm doing wrong?

    By *Lose control of my speed* I mean whichever way I'm moving at that point where my speed starts to go back down, I cant change directions for at least a second.(its like im on ice at that point)

    these are the only two functions that deal with my speed and my Checks function which right now only checks to see if im grounded

    Code (CSharp):
    1.     void Checks () // Standard checks
    2.     {
    3.  
    4.         // START GROUND CHECK
    5.         if (Physics.Raycast(transform.position, -transform.up, out normalHit, playerToNormalRay, groundMask)) // Checks to see if the player is grounded.
    6.         {
    7.             isGrounded = true;
    8.         }
    9.         else
    10.         {
    11.             isGrounded = false;
    12.         }
    13.         // END GROUND CHECK
    14.     }
    This function is just for basic input and movement.

    Code (CSharp):
    1.     void Movement() // Players base movement
    2.     {
    3.        // Debug.Log(_moveDirection);
    4.         _moveDirection = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, Input.GetAxis("Jump") * jumpForce, Input.GetAxisRaw("Vertical") * moveSpeed); // Vector3 for movement input.
    5.  
    6.         if (isGrounded) // Stops the player from moving while airborne
    7.         {
    8.             if (rb.velocity.magnitude < curSpeed /* moveSpeed */) // Stops the speed from multiplying out into neverland
    9.            {
    10.                rb.AddRelativeForce(_moveDirection); // Using AddRelativeForce to move based on the players forward      
    11.            }
    12.  
    13.         }
    14.     }
    moveSpeed is a float set to 15
    _moveDirection is a Vector3
    rb is the Rigidbody.

    Below is where I think my problem lies (in the lerps)

    This function handles the speed boost with lerps to ramp the speed up and then back down.
    The part that handles the speed ramps starts with the if statement with the speedChange bool in the () brackets.

    Code (CSharp):
    1.  void PlayerMomemtum() // Players Speed Momemtum
    2.     {
    3.  
    4.  
    5.         playersYVelocity = rb.velocity.y; // Players Y velocity at all times.
    6.  
    7.         if (isGrounded && playersYVelocity < 0 && velocitySwitch) // Runs once when the player is grounded, falling, and when the check velocitySwitch is reset.
    8.         {
    9.             playersYContactVelocity = playersYVelocity; // Grabs the last instance of playersYVelocity before hitting the ground.
    10.                                                         //    rb.drag = playersLiftOffDrag;
    11.             speedChange = true;
    12.             velocitySwitch = false;
    13.  
    14.         }
    15.         else if (playersYVelocity > 0) // Resets velocityGrab when the Player is going upwards in world space.
    16.         {
    17.             velocitySwitch = true;
    18.  
    19.         }
    20.  
    21.         if (speedChange)
    22.         {
    23.             curSpeed = Mathf.Lerp(curSpeed, maxSpeed, Time.deltaTime);
    24.             if (curSpeed > maxSpeed - 1)
    25.             {
    26.                 speedChange = false;
    27.             }
    28.         }
    29.         else if (speedChange == false)
    30.         {
    31.             curSpeed = Mathf.Lerp(curSpeed, minSpeed, Time.deltaTime);
    32.         }
    33.  
    34.     }
    playerYVelocity is a float.
    curSpeed is the current speed
    minSpeed is set to 15
    maxSpeed is set to 25
    All are floats

    All functions are in Update

    Let me know if I need to include more, any help is greatly appreciated.
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    For starters, your lerp is incorrect. Since you have moving targets, you should use Mathf.MoveTowards instead.

    As for your actual issue: You're using AddRelativeForce, which creates an accumulation of force over time. The reason you feel like you're sliding on ice is because your new forces have to overcome the previous forces before your character starts moving in the other direction. If you want snappy Megaman style movement, set the velocity explicitly instead.
     
    Hotpockets26 likes this.
  3. Hotpockets26

    Hotpockets26

    Joined:
    Dec 16, 2017
    Posts:
    32
    Thank you, I added Mathf.MoveTowards and it did make my momement alittle smoother, but my main problem seemed to be with the following code
    Code (CSharp):
    1.  if (isGrounded) // Stops the player from moving while airborne
    2.         {
    3.             if (rb.velocity.magnitude < curSpeed) // Stops the speed from multiplying out into neverland
    4.            {
    5.                rb.AddRelativeForce(_moveDirection); // Using AddRelativeForce to move based on the players forward    
    6.            }
    7.         }
    The rb.velocity.magnitude would be more than my curSpeed when I was ramping my speed down to minSpeed.

    So after toying with it for about an hour I said screw it and Decided to clamp my speed instead, Below is the finished code.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerMovement : MonoBehaviour
    6. {
    7.     private Rigidbody rb; // Rigidbody of the Player Capsule.
    8.  
    9.     public float moveSpeed = 15f; // Input Move Speed of the player.
    10.     public Vector3 _moveDirection; // Stores player input for movement.
    11.  
    12.     public float playerToNormalRay = 1.1f; // Distance Ray for keeping the same rotation as the normal below the player(while grounded or hitting air off a ramp)
    13.     public float airToGroundCorrectionRay = 15f; // Distance Ray for rotating toward the ground when the player is airborne(not hitting anything with playerToNormalRay)
    14.     public LayerMask groundMask; // Layer Mask for the ground/ramps
    15.  
    16.     private Vector3 newUp; // The players transform.up, based on the normal below the player(Used to keep the player have the same up as the normal below).
    17.  
    18.     public bool isGrounded; // checks to see if the player is grounded.
    19.     RaycastHit normalHit; // used to store the objects normal below the player in the newUp vector3(Used to keep the player have the same up as the normal below).
    20.  
    21.     public float jumpForce = 50f;
    22.  
    23.     // PlayerMomentum
    24.     float playersYVelocity; // Players Y Velocity at all times.
    25.     float playersYContactVelocity; // The players Y velocity at point of contact with Ground Mask(when player isGrounded == true)
    26.     public float minSpeed = 15f; // The minimum speed of the player
    27.     public float curSpeed; // The current speed of the player
    28.     public float maxSpeed = 25f; // The Maximum speed of the player
    29.     public bool velocitySwitch = false; // Used to reset playersYContactVelocity when the player starts going upward in world space.
    30.     public float speedIncrement = 1.0f;
    31.     public float speedDecrement = 1.0f;
    32.     public bool speedChange = false;
    33.  
    34.     //DEBUG VARIABLES BELOW
    35.  
    36.    
    37.  
    38.     // Use this for initialization
    39.     void Start()
    40.     {
    41.         rb = gameObject.GetComponent<Rigidbody>(); // Stores the Players Rigidbody in the rb variable
    42.  
    43.         curSpeed = minSpeed; // Sets the current speed to be at the minimum amount of speed posiable at the beginning of the game.
    44.     }
    45.  
    46.     // Update is called once per frame
    47.     void Update()
    48.     {
    49.         Checks(); // Standard checks
    50.  
    51.         Movement();  // players base movement
    52.  
    53.         PlayerRotation(); // Rotation of the player on ramps
    54.  
    55.         PlayerMomemtum(); // Players Speed Momemtum
    56.  
    57.         //DEBUGING BELOW
    58.  
    59.             // RAYCASTING
    60.        
    61.         Debug.DrawRay(transform.position, transform.up * 5, Color.green); // Used just as a visual to see which way the player is rotated.
    62.         Debug.DrawRay(transform.position, -transform.up * playerToNormalRay, Color.red); // testing for the red up close normal ray.
    63.         Debug.DrawRay(transform.position, Vector3.down * airToGroundCorrectionRay, Color.blue); // testing for the blue ground correction ray
    64.  
    65.            // END RAYCASTING
    66.  
    67.     }
    68.    
    69.     void Checks () // Standard checks
    70.     {
    71.  
    72.         // START GROUND CHECK
    73.         if (Physics.Raycast(transform.position, -transform.up, out normalHit, playerToNormalRay, groundMask)) // Checks to see if the player is grounded.
    74.         {
    75.             isGrounded = true;
    76.         }
    77.         else
    78.         {
    79.             isGrounded = false;
    80.         }
    81.         // END GROUND CHECK
    82.     }
    83.  
    84.     void Movement() // Players base movement
    85.     {
    86.         _moveDirection = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, Input.GetAxis("Jump") * jumpForce, Input.GetAxisRaw("Vertical") * moveSpeed); // Vector3 for movement input.
    87.  
    88.         if (isGrounded) // Stops the player from moving while airborne
    89.         {
    90.             rb.velocity = Vector3.ClampMagnitude(rb.velocity, curSpeed); // Keeps the speed of the player from multiplying off into neverland. *curSpeed is determined in the PlayerMomentum Function*
    91.             rb.AddRelativeForce(_moveDirection); // Using AddRelativeForce to move based on the players forward  
    92.         }
    93.     }
    94.  
    95.     void PlayerRotation() // Rotation of the player Capsule.
    96.     {
    97.  
    98.        if (Physics.Raycast(transform.position, -transform.up, out normalHit, playerToNormalRay)) // Rotates the player while on ground, ramps, and on false air. (RED Ray)
    99.         {
    100.             newUp = normalHit.normal; // Putting the hit.normal in the vector3 newUp to make the players rotation the same as the below objects normal direction.
    101.         } else if(Physics.Raycast(transform.position, Vector3.down, out normalHit, airToGroundCorrectionRay, groundMask)) // Rotates the player toward the rotation of the ramp or ground below when the player is completely airborne(aka no ground, ramp or false air just below the player). (BLUE Ray)
    102.         {    
    103.             newUp = normalHit.normal; // Putting the hit.normal in the vector3 newUp to make the players rotation the same as the below objects normal direction.
    104.         }
    105.  
    106.         transform.up = newUp; // Setting the up position of the character based on the newUp vector3.
    107.        
    108.     }
    109.  
    110.     void PlayerMomemtum() // Players Speed Momemtum
    111.     {
    112.  
    113.         playersYVelocity = rb.velocity.y; // Players Y velocity at all times.
    114.  
    115.         if (isGrounded && playersYVelocity < 0 && velocitySwitch) // Runs once when the player is grounded, falling, and when the check velocitySwitch is reset.
    116.         {
    117.             playersYContactVelocity = playersYVelocity; // Grabs the last instance of playersYVelocity before hitting the ground.
    118.             speedChange = true; // Starts ramping the speed up to maxSpeed once the player hits Ground.
    119.             velocitySwitch = false; // Causes this if statement to run 1 time once the player hits Ground
    120.  
    121.         }
    122.         else if (playersYVelocity > 0) // Resets velocitySwitch when the Player is going upwards in world space.
    123.         {
    124.             velocitySwitch = true;
    125.  
    126.         }
    127.  
    128.         if (speedChange) // Starts ramping the speed up to maxSpeed once the player hits Ground.
    129.         {
    130.             curSpeed = Mathf.MoveTowards(curSpeed, maxSpeed, Time.deltaTime * speedIncrement);
    131.             if (curSpeed > maxSpeed - 1) // Resets the speedChange when the curSpeed hits maxSpeed
    132.             {
    133.                 speedChange = false;
    134.             }
    135.         }
    136.         else if (speedChange == false) // Runs after the Speed has ramped up to maxSpeed
    137.         {
    138.             curSpeed = Mathf.MoveTowards(curSpeed, minSpeed, Time.deltaTime * speedIncrement); // Ramps the speed back down to minSpeed
    139.         }
    140.  
    141.     }
    142.  
    143. }
    Sorry for all the comments..... I go overboard on comments.....

    Thanks for your help!
     
    GroZZleR likes this.
  4. Arqae

    Arqae

    Joined:
    Nov 15, 2018
    Posts:
    4
    How would you make the movement more snappy, like for example if you would ramp it up to max speed and then instantly set the speed to zero if stop moving ?