Jonathan
Jonathan

Reputation: 325

Unity 5: How to slow down rigidbody naturally instead of sudden stop

I'm using this:

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }
}

to move my character forward in the air (using jetpack). When I let go of the joystick my character stops immediately. What I want is that the character keeps moving forward after joystick is released and with time slow down and gradually stop. It looks stupid that my character stops like it hit a wall. What kind of force/velocity/transform I should use so that physics slow down my character after I let go of the joystick?

My rigidbody settings:

Character also has a capsule collider that is NOT trigger and has no physics material.

EDIT: here is the full code so you can see if there is any conflicts in my code

using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;

public class JetpackController : MonoBehaviour{

    Rigidbody rb;

    // controller axes
    [SerializeField]
    public string speedAxis = "Vertical";
    public string rotateAxis = "HorizontalRotate";

    [SerializeField]
    public float forwardSpeed;
    public float upSpeed;
    public float rotateSpeed;
    public float rotationIgnoreZone;
    public float MAX_HEIGHT;

    float speedInput;
    float rotateInput;
    public bool leftJoystick;
    public bool rightJoystick;

    ParticleSystem jetpackFire1;

    Vector3 originalGravity;

    // access Joystick script in Standard assets to detect when right joystick is held down
    Joystick joystick_left;
    Joystick joystick_right;

    void Start () {
        if (GetComponent<Rigidbody> ()) {
            rb = GetComponent<Rigidbody> ();
        } else {
            Debug.LogError ("Player needs to have a rigidbody.");
        }

        // get Joysticks
        if (GameObject.Find ("MobileJoystick_left").GetComponent<Joystick> ()) {
             joystick_left = GameObject.Find ("MobileJoystick_left").GetComponent<Joystick> ();
         } else {
             Debug.LogError ("Either gameobject with name 'MobileJoystick_right' does not exist in the scene or it does not have script called Joystick.cs attached to it.");
        }
        if (GameObject.Find ("MobileJoystick_right").GetComponent<Joystick> ()) {
            joystick_right = GameObject.Find ("MobileJoystick_right").GetComponent<Joystick> ();
        } else {
            Debug.LogError ("Either gameobject with name 'MobileJoystick_right' does not exist in the scene or it does not have script called Joystick.cs attached to it.");
        }

        jetpackFire1 = GameObject.Find("JetpackFire1").GetComponent<ParticleSystem> ();
        jetpackFire1.playbackSpeed = 5.0f;

        originalGravity = Physics.gravity;
    }

    void FixedUpdate () {

        GetInput ();

        // move forward and backward according to left joysticks input
        if(leftJoystick){
            // left joystick held down
            rb.AddRelativeForce(0, 0, forwardSpeed*speedInput, ForceMode.Impulse);
        }

        // if right joystick is used
        if (rightJoystick) {
            jetpackFire1.Play ();

        if (transform.position.y < MAX_HEIGHT) {
            // allow going up
            //rb.AddRelativeForce (0, upSpeed, 0, ForceMode.Impulse);
            rb.AddForce(transform.forward * forwardSpeed);
        } else if (transform.position.y >= MAX_HEIGHT) {
            // prevent player to go any further up and also falling
            Physics.gravity = Vector3.zero; // no gravity to prevent player from falling
            rb.velocity = Vector3.zero;
        }
            // rotate
            // always keep rotating (player can go past look at joystick dir)
            if (rotateInput >= rotationIgnoreZone || rotateInput <= -rotationIgnoreZone) {
                transform.Rotate(Vector3.up * rotateInput, Time.deltaTime * rotateSpeed);
            }
    } else {
            jetpackFire1.Stop ();
            // if right joystick is released
            Physics.gravity = originalGravity; // normal gravity -> player can fall
        }

    } 

public void GetInput(){
    speedInput = CrossPlatformInputManager.GetAxis (speedAxis);
    rotateInput = CrossPlatformInputManager.GetAxis (rotateAxis);
    // access Joystick.cs script to grab wether right joystick is pressed or not
    leftJoystick = joystick_left.leftJoystickPressed;
    rightJoystick = joystick_right.rightJoystickPressed;
}

}

Upvotes: 3

Views: 26263

Answers (3)

J.Small
J.Small

Reputation: 96

You could do a simple linear slow down.

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }
    
    if(noJoystick){
        rb.velocity = rb.velocity * 0.9f;
    }
}

Note that the update function gets called on frame update, so I would suggest putting this in a FixedUpdate() function that way the slow rate won't depend on the frame rate.

Upvotes: 0

Trigary
Trigary

Reputation: 431

Can't comment yet

Like J.Small said, you could multiply the velocity with a number around 0.95 to slowly slow the rigidbody down. If you put the multiplication in the Update method I suggest you to multiply the ~0.95 number with Time.deltaTime, so the velocity decrease will be proportional to the passed time.

void Update(){
    if(leftJoystick){
        rb.AddRelativeForce(0, 0, 400f, ForceMode.Impulse);
    }

    if(noJoystick){
        rb.velocity = rb.velocity * 0.95f * Time.deltaTime;
        //Or: rb.velocity.x
    }
}

You could also apply a small amount of force instead of multiplying the velocity if you want to slow down the rigidbody in a more configurable way (the amount should be based on Time.deltaTime if you put it into Update - which gets called once a frame), but the method above is easier.

Upvotes: 2

Guest Person
Guest Person

Reputation: 21

I'm not a pro at coding, so I'm not sure if this'll work for everyone, but I tried something like this to fix a similar issue.

    void FixedUpdate()
    {
        playerRigidbody.AddRelativeForce(Vector2.up * forwardInput * playerSpeed * Time.fixedDeltaTime);

        if (forwardInput <= 0)
        {
            playerRigidbody.velocity = playerRigidbody.velocity / 1.005f; // <-- This will gradually slow down the player when they're idle.
        }
    } 

Upvotes: 2

Related Questions