Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How can I make CharacterController accelerate according to Animation Curve?

Discussion in 'Scripting' started by trmhtk2_unity, Nov 25, 2022.

  1. trmhtk2_unity

    trmhtk2_unity

    Joined:
    Mar 29, 2020
    Posts:
    35
    I'm trying to make my player based on CharacterController accelerate according to the Animation Curve - I tried to do the following code but the player moves as usual and does not accelerate (and yes, I set the Curve to Ease in in the Editor and the startMoveTime variable to about 10)
    Help, anyone?

    Code (CSharp):
    1.    private void Update() {
    2.         Gravity();
    3.  
    4.         Movement();
    5.      
    6.  
    7.         Animations();
    8.  
    9.     private void Movement() {
    10.  
    11.         float horizontalInput = Input.GetAxis("Horizontal");
    12.         float verticalInput = Input.GetAxis("Vertical");
    13.  
    14.         Vector2 currentMovementInput = new Vector2(horizontalInput, verticalInput);
    15.  
    16.  
    17.         float moveTime = 0f;
    18.         if (oldMovementInput == Vector2.zero) {
    19.             if (currentMovementInput != Vector2.zero)  {
    20.                 //stop curve
    21.                 canMove = false;
    22.  
    23.                 float curveTime = 0;
    24.                 while (curveTime < curve.keys[curve.keys.Length -2].value curveTime < startMoveTime) {
    25.                     curveTime += .1f + Time.deltaTime;
    26.                     curveAddtive = startMoveCurve.Evaluate(curveTime);
    27.  
    28.  
    29.                     Debug.Log(curveAddtive);
    30.  
    31.                     // MotionCurve(startMoveCurve, ref curveAddtive, ref canMove);
    32.                     Vector3 movementCurve = Quaternion.Euler(0, followCamera.transform.eulerAngles.y, 0) * new Vector3(horizontalInput * curveAddtive, 0, verticalInput * curveAddtive);
    33.                     Vector3 movementCurveNormalized = movementCurve.normalized;
    34.                     moveTime += Time.deltaTime;
    35.                     if (moveTime < startMoveTime) {
    36.  
    37.                     controller.Move(movementCurveNormalized * .3f * Time.deltaTime);
    38.                     }
    39.                     //    endMoveCurve.
    40.                     //while()
    41.                 }
    42.                     canMove = true;
    43.             }
    44.         }
    45.  
    46.         oldMovementInput = new Vector2(horizontalInput, verticalInput);
    47.  
    48.         Vector3 movementInput = Quaternion.Euler(0, followCamera.transform.eulerAngles.y, 0) * new Vector3(horizontalInput, 0, verticalInput);
    49.  
    50.         Vector3 movementDirection = movementInput.normalized;
    51.  
    52.         if(movementDirection != Vector3.zero) {
    53.             isWalking = true;
    54.  
    55.             Quaternion desiredRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
    56.  
    57.             transform.rotation = Quaternion.Slerp(transform.rotation, desiredRotation, rotationSpeed * Time.deltaTime);
    58.         } else {
    59.             isWalking = false;
    60.         }
    61.         if (canMove) {
    62.         controller.Move(movementDirection * movementSpeed * Time.deltaTime);
    63.         }
    64.     }
     
  2. kruskal21

    kruskal21

    Joined:
    May 17, 2022
    Posts:
    68
    I have taken a look at the code, and I think there are two potential problems here:

    1. It looks like the main method of moving the character is by calling controller.Move(). On line 37 you are passing movementCurveNormalized. However, normalizing a Vector3 will make it have a magnitude of 1. Meaning no matter what value comes out of the startMoveCurve.Evaluate, movementCurveNormalized will always have a magnitude of 1.
    • Solution: don't normalize the vector and use movementCurve instead.
    2. The code for acceration (starting at line 23) is in a while loop. A while loop stops all other code from running until it is finished. Meaning all the acceleration happens in a single frame, not over time. Code for acceleration should happen over multiple frames without a while loop.
    • Solution: remove the while loop, convert curveTime from a local variable to a class variable.
    Modelling acceleation is usually pretty simple. The basic idea is:
    Code (CSharp):
    1. class MyController : MonoBehaviour
    2. {
    3.     public float acceleration;
    4.     public float maxSpeed;
    5.  
    6.     private float speed;
    7.  
    8.     void Update()
    9.     {
    10.         speed += acceleration * Time.deltaTime;
    11.         speed = Mathf.Min(maxSpeed, speed);
    12.  
    13.         // Do movement with speed...
    14.     }
    15. }
    You can consider using an animation curve like you are doing, but usually acceleration can be assumed to be constant in most cases and makes for simpler code.