How do I implement momentum for a ball that moves based on directional movement input?

Viewed 65

How can I make my ball roll a little bit further after I release the w,a,s,d keys (directional movement keys)? Currently, if I stop pressing w,a,s,d, the ball just stops moving immediately, but I'd like it to have momentum and keep rolling a bit after I release the keys.

Here is what I've written so far:

public float speed = 6f;

public float turnSmoothTime = 0.1f;
float turnSmoothVelocity;


// Update is called once per frame
void Update()
{
    float horizontal = Input.GetAxisRaw("Horizontal");
    float vertical = Input.GetAxisRaw("Vertical");
    Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;

    if(direction.magnitude >= 0.1f)
    {
        float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
        float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
        transform.rotation = Quaternion.Euler(0f, angle, 0f);

        Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
        controller.Move(moveDir.normalized * speed * Time.deltaTime);

    }
}
2 Answers

Basically add physics and momentum. A key press equalizer expertise force/transfer energy (E=0.5mv^2 ro get the speed) Every update a fractioneel force is applied (see wiki, constant + v^3 if I remember correct)

Result is a ball that gradually gains speed, granulaat slows down and does not change direction immediatly. Make the friction big compared to the force to make controle snappen.

The best approach would be to use a rigidbody to intereact with the physics engine (the effect you are looking for would be easier achieved this way). However, if you rather use a character controller then I suggest first creating a method to execute your input (example / psuedocode):

void MovePlayer(moveDir) {
 
    // Your moving logic
}

Next, you could create a timer that automatically calls this method for an 'x' amount of time after your input is stopped (example / psuedocode):

float rollTimer = 0;

void Update() {

    float horizontal = Input.GetAxisRaw("Horizontal");
    float vertical = Input.GetAxisRaw("Vertical");

    // Add your logic to calculate when to activate the rolling effect
    // possibly a toggle based on your horizontal & vertical input
    timer = (horizontal != 0 && vertical != 0) ? 0 : 3;
    
    // Add an if statement, so that you arent constantly setting timer to 0
    if(timer > 0) {

         while(timer > 0) {
            
             MovePlayer(/* Simulated input */);
             rollTimer -= time.deltaTime;
         }

         // Reset the timer
         rollTimer = 0;
    }        
}

I can not test this right now, so you may have to tweak it more to fit your exact code, but the concept remains true. This is the simpliest logic I could think of that doesn't use a rigidbody. If you decide to switch to a rigidbody approach, then you can just use the AddForce() method which can give the same effect with natural looking results from the physics engine.

Related