3
votes

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:

  • Mass: 100
  • Drag: 0
  • Angular drag: 0.05
  • Uses gravity
  • Not kinematic
  • Interpolate: interpolate
  • Collision detection: Discrete
  • Freeze position: none
  • Freeze rotation: all

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;
}

}

3
The only place I see you possibly halting your rigidbody is when transform.position.y >= MAX_HEIGHT. Can you check whether that if statement somehow gets entered?Serlite
I added Debug.Log("Can you see me?") in that if statement to check when it triggers. As expected it only triggers if players y position exceeds 15 (MAX_HEIGHT = 15f). If I release the joystick before ever exceeding y position 15, problem still remains.Jonathan
You halt velocity when they go above MAX_HEIGHT. Perhaps you should Lerp Y direction velocity when they get near max height, and allow horizontal velocity to continue normally. Lerp would simulate "lack of oxygen" for the pack, and prevent the same "Hit wall" kind of feeling when they reach max height.Chuck Savage

3 Answers

2
votes

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.95 * 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.

2
votes

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.
        }
    } 
0
votes

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.9;
    }
}

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.