AJ Tech
AJ Tech

Reputation: 75

Smooth fall in Unity - C#

I am working on a Character Controller Script and everything is working fine but the problem is that once my player starts to fall it is so sudden and jerks down. I would like the player to gradually fall down, this is my character controller script -

using UnityEngine;
using System.Collections;

public class CharacterController : MonoBehaviour {

    public float inputDelay = 0.1f;
    public float forwardVel = 12;
    public float rotateCel = 12;
    public float JumpHeight = 20;
    public Vector3 Gravity = new Vector3 (0, -180, 0);
    public bool CanPress;
    private float jumpTime;
    public float _initialJumpTime = 0.4f;
    //[HideInInspector]
    public bool isGrounded;
    Quaternion targetRotation;
    Rigidbody rBody;
    Vector3 forwardInput, turnInput;
    public bool HasJumped;

    public Quaternion TargetRotation
    {
        get {return targetRotation;}
    }
    // Use this for initialization
    void Start () {
        Physics.gravity = Gravity;
        targetRotation = transform.rotation;
        if (GetComponent<Rigidbody> ())
            rBody = GetComponent<Rigidbody> ();
        else {
            Debug.LogError("Character Needs Rigidbody");
        }

    //  forwardInput = turnInput = 0;
        forwardInput = turnInput = Vector3.zero;
    }

    // Update is called once per frame
    void Update () {

        GetInput ();
        //Turn ();

        if (CanPress == true) {
            if (Input.GetKeyDown (KeyCode.Space)) { 
                HasJumped = true;
                jumpTime = _initialJumpTime;
            }
        }

        if (HasJumped == true) {
            rBody.useGravity = false;
            jumpTime -= 1 * Time.deltaTime;
            if (jumpTime > 0) {
            Jump();
            }
            else {
                HasJumped = false;
                rBody.useGravity = true;
            }
        }
    }


    void GetInput() {
        //forwardInput = Input.GetAxis ("Vertical");
        //turnInput = Input.GetAxis ("Horizontal");
        forwardInput = new Vector3 (Input.GetAxis ("Horizontal") * rotateCel, 0, Input.GetAxis ("Vertical") * forwardVel);
        forwardInput = transform.TransformDirection (forwardInput);
        if (Input.GetKeyUp (KeyCode.Space)) {
            //HasJumped = false;
        }


    }

    void Jump() { 

            Vector3 up = transform.TransformDirection (Vector3.up);
        GetComponent<Rigidbody> ().AddForce (up * 5, ForceMode.Impulse);

    }
    void FixedUpdate() {

        Run ();
    }
    void Run() {
        if (Mathf.Abs (10) > inputDelay) {
            //Move
            //rBody.velocity = transform.forward * forwardInput * forwardVel;
            rBody.velocity = forwardInput;
        } else {
            //zero velocity
            rBody.velocity = Vector3.zero;

        }

    }
    void Turn() {
    //  targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
    //  transform.rotation = targetRotation;
    }

    void OnTriggerEnter(Collider col) {
        isGrounded = true;
        CanPress = true;
    }

    void OnTriggerExit(Collider col) {
        isGrounded = false;
        CanPress = false;
    }

}

My character has a Rigidbody attactches which uses gravity and has X,Y,Z constraints for Rotation.

Thanks for the help. :)

Upvotes: 1

Views: 1902

Answers (1)

Tom
Tom

Reputation: 2472

Okay, so I took your code and had a play.

I think the issue was that in your Run() function, you were altering the velocity of the rigidbody which was affecting your jumping.

I've taken that stuff out and improved your script slightly and tested it. Attach this to a capsule with a rigidbody on it, with a floor underneath with a box collider on and hit space, and you should get a smooth jump.

Your new(ish) script:

using UnityEngine;
using System.Collections;

public class CharacterController : MonoBehaviour
{
    public float inputDelay = 0.1f;
    public float forwardVel = 12;
    public float rotateCel = 12;
    public float jumpHeight = 10;
    private float jumpTime;
    public float _initialJumpTime = 0.4f;
    //[HideInInspector]
    public bool isGrounded;
    Quaternion targetRotation;
    Rigidbody rBody;
    Vector3 forwardInput, turnInput;
    public bool canJump;

    public Quaternion TargetRotation
    {
        get { return targetRotation; }
    }

    void Start()
    {
        targetRotation = transform.rotation;
        if (GetComponent<Rigidbody>())
            rBody = GetComponent<Rigidbody>();
        else
        {
            Debug.LogError("Character Needs Rigidbody");
        }

        //  forwardInput = turnInput = 0;
        forwardInput = turnInput = Vector3.zero;
    }

    void Update()
    {
        GetInput();
        //Turn ();

        if (Input.GetKeyDown(KeyCode.Space) && canJump)
        {
            rBody.AddForce(Vector3.up * jumpHeight, ForceMode.Impulse);
        }
    }


    void GetInput()
    {
        //forwardInput = Input.GetAxis ("Vertical");
        //turnInput = Input.GetAxis ("Horizontal");
        forwardInput = new Vector3(Input.GetAxis("Horizontal") * rotateCel, 0, Input.GetAxis("Vertical") * forwardVel);
        forwardInput = transform.TransformDirection(forwardInput);
    }

    void FixedUpdate()
    {
        //Run();
    }

    void Run()
    {
        //HERE YOU SET THE RIGIDBODYS VELOCITY, WHICH IS CAUSING YOUR JUMP TO NOT WORK PROPERLY. DO NOT MODIFY THE VELOCITY
        //OF A RIGIDBODY
        if (Mathf.Abs(10) > inputDelay)
        {
            //Move
            //rBody.velocity = transform.forward * forwardInput * forwardVel;
            rBody.velocity = forwardInput;
        }
        else
        {
            //zero velocity
            rBody.velocity = Vector3.zero;
        }
    }

    void Turn()
    {
        //  targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
        //  transform.rotation = targetRotation;
    }

    void OnCollisionEnter(Collision col)
    {
        isGrounded = true;
        canJump = true;
    }

    void OnCollisionExit(Collision col)
    {
        isGrounded = false;
        canJump = false;
    }
}

Couple of points:

  • name your variables inThisKindOfFashion (jumpHeight, isOnGround, camelCaseExample), having variables beginning with a capital letter like Gravity and JumpHeight can get confusing.

  • as someone once answered on one of my questions, don't modify the velocity of a rigidbody unless you know what you are doing! Seems odd, but after following that advice I've never had a problem since!

  • In your script I have used OnCollision rather than OnTrigger. If you put a floor with a box collider underneath your capsule with a collider, rigidbody and this script on, your character will stop on the ground. If you use a trigger, he will fall through (at least in my experience!)

Happy coding! :-)


Edit To respond to your comments:

"How do you suggest I move the player"

Movement can be done in a variety of different ways, but I usually use this one all the time unless I need to do something a bit differently:

void Update()
{
    if (Input.GetKeyDown(KeyCode.LeftArrow))
    {
        transform.position += Vector3.left * speed * Time.deltaTime; //speed could be 5f, for example (f means float);
    }

    // then do the same for other directions, RightArrow -.right, UpArrow - .forward, DownArrow - .back
}

"How do I adjust how fast the player jumps"

You can alter the jumpHeight variable for a higher or smaller jump. If by faster you mean falls down faster, go to Edit>Project Settings>Physics> and change Y gravity to something smaller, such as -20.

Tutorials can be found here

They have a wide variety of tutorials, and even have ones that come with example projects so you can just put it together following the video.

Upvotes: 1

Related Questions