[SOLVED] My character can`t jump when he is not moving

(Sorry for mistakes because I`m not native English speaker)

I`m writing physycal movement script(using RigidBody). My character seemed very slippery, as if he was walking on ice and slipping after stopping. So, I added a few lines to the code to wrap the acceleration if the moving keys(WASD) are not pressed and stop moving. Here yhey are:

 if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") == 0 && grounded)
        {
            rigidbody.velocity = myVector;
            myVector.x = Mathf.SmoothDamp(rigidbody.velocity.x, 0, ref walkDeaccelerationVolx, walkDeacceleration);
            myVector.z = Mathf.SmoothDamp(rigidbody.velocity.z, 0, ref walkDeaccelerationVolz, walkDeacceleration);
        }

I think that my “grounded” does not have time to change the value to “false” and my “walkDeacceleraion” applied to jump too.
But if my character is moving there are no problems with the jump.

I want to add that if you make many attempts to jump, then with some attempt it will work, but it’s all by random.

Help me make a normal jump that will work as it should!)

And yes, here is the whole code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovementScript : MonoBehaviour
{
    Rigidbody rigidbody;
    public GameObject camera;
    public float walkAccelAirRatio=0.1f;
    public float walkAcceleration = 5;
    public float walkDeacceleration = 5;
    float walkDeaccelerationVolx;
    float walkDeaccelerationVolz;
    public float maxWalkSpeed = 20;
    float velocityX ;
    float velocityZ ;
    Vector2 horizontalMovement;

    Vector3 myVector;

    public float jumpVelocity=20;
    public bool grounded=false;
    public float maxSlope = 60;


    void Start()
    {
        rigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        horizontalMovement = new Vector2(rigidbody.velocity.x, rigidbody.velocity.z);
        if (horizontalMovement.magnitude>maxWalkSpeed)
        {
            horizontalMovement=horizontalMovement.normalized;
            horizontalMovement *= maxWalkSpeed;
        }

        rigidbody.velocity = new Vector3(horizontalMovement.x, rigidbody.velocity.y, horizontalMovement.y);

        if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") == 0 && grounded)
        {
            rigidbody.velocity = myVector;
            myVector.x = Mathf.SmoothDamp(rigidbody.velocity.x, 0, ref walkDeaccelerationVolx, walkDeacceleration);
            myVector.z = Mathf.SmoothDamp(rigidbody.velocity.z, 0, ref walkDeaccelerationVolz, walkDeacceleration);
        }

        transform.rotation = Quaternion.Euler(0, camera.GetComponent<MouseLookScript>().currentYRotation, 0);

        if(grounded)
            rigidbody.AddRelativeForce(Input.GetAxis("Horizontal") * walkAcceleration * Time.deltaTime, 0, Input.GetAxis("Vertical") * walkAcceleration * Time.deltaTime);
        else
            rigidbody.AddRelativeForce(Input.GetAxis("Horizontal") * walkAcceleration * walkAccelAirRatio * Time.deltaTime, 0, Input.GetAxis("Vertical") * walkAcceleration * walkAccelAirRatio * Time.deltaTime);


        if (Input.GetButtonDown("Jump")&&grounded)
        {
            rigidbody.AddForce(0, jumpVelocity, 0);
        }
    }

    private void OnCollisionStay(Collision collision)
    {
        foreach(ContactPoint contact in collision.contacts)
        {
            if (Vector3.Angle(contact.normal, Vector3.up) < maxSlope)
                grounded = true;
        }
    }

    private void OnCollisionExit(Collision collision)
    {
        grounded = false;
    }
}

In the first code you posted, myVector.y will be 0f since you’re not setting it to anything else anywhere in your code. I would assume that a jump results in a Y velocity greater than 0, so you’re cancelling the jump basically whenever you set velocity to myVector.

Also, don’t add forces or set velocity in Update. That stuff goes in FixedUpdate or you’ll get significantly different behavior depending on frame rate. (don’t just change the entire Update method to FixedUpdate either. You should be checking for Input in Update still)

Right now, your damping code says:

  1. Completely ignore my current velocity (including the Y velocity), and instead replace it with the value of “myVector”
  2. Move the X and Z components of “myVector” a little closer to zero (this has no effect on your velocity until we apply step 1 in the next frame)

You probably meant something more like this:

Vector3 tempVector = rigidbody.velocity;
tempVector.x = Mathf.SmoothDamp(tempVector.x, 0, ref walkDeaccelerationVolx, walkDeacceleration);
tempVector.z = Mathf.SmoothDamp(tempVector.z, 0, ref walkDeaccelerationVolz, walkDeacceleration);
rigidbody.velocity = tempVector;

My modified version says:

  1. Make a copy of our current velocity
  2. In that copy, move the X and Z components a little closer to zero
  3. Use that modified copy as the new velocity

It might also be a good idea to change walkDeaccelerationVol x/z to match your rigidbody’s current acceleration (which will probably be zero) during the first frame of the damping. That would be a more complex change. I haven’t used SmoothDamp before and the documentation isn’t as explicit as it could be, but it seems to expect that variable to be the rate of change from the previous frame, and right now that isn’t guaranteed to be true.

1 Like

Honestly, I can’t understand how this works, because I just started learning C # for Unity, but it helped! Thank you very much)
Also thanks to everyone who responded)

The key thing to remember about computer programming is that computers will always do exactly what you asked, no matter how ridiculous that is. They do not understand context; they do not infer your intent. It’s kind of like talking to an evil genie: you can get your wishes granted, but you better phrase your wishes just right, because you’re going to get what you asked for rather than what you meant.

Something went wrong. When I changed my part of the code to yours the jump became normal but now the character slides again, lol.

If you want help debugging a new problem, post your new code.

How long does the character slide? The code in your OP has walkDeacceleration = 5 (unless it’s overridden in the Unity inspector), which means it should take 5 seconds to come to a complete stop. (Remember that your old code was basically setting velocity to zero instantaneously because of your bug, and so previously the value of this parameter didn’t really matter.)

If you want your character to stop instantly then don’t bother with the SmoothDamping and just set the X and Z components to zero.

For realism, I do not want the character to stop instantly, but to slide quite a bit regardless of speed

My new code(it only changed lines 42 to 45):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovementScript : MonoBehaviour
{
    Rigidbody rigidbody;
    public GameObject camera;
    public float walkAccelAirRatio=0.1f;
    public float walkAcceleration = 1;
    public float walkDeacceleration = 1;
    float walkDeaccelerationVolx;
    float walkDeaccelerationVolz;
    public float maxWalkSpeed = 20;
    float velocityX ;
    float velocityZ ;
    Vector2 horizontalMovement;
    Vector3 myVector;
    public float jumpVelocity=20;
    public bool grounded=false;
    public float maxSlope = 60;


    void Start()
    {
        rigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        horizontalMovement = new Vector2(rigidbody.velocity.x, rigidbody.velocity.z);
        if (horizontalMovement.magnitude>maxWalkSpeed)
        {
            horizontalMovement=horizontalMovement.normalized;
            horizontalMovement *= maxWalkSpeed;
        }

        rigidbody.velocity = new Vector3(horizontalMovement.x, rigidbody.velocity.y, horizontalMovement.y);

        if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") == 0 && grounded)
        {
            myVector=rigidbody.velocity;
            myVector.x = Mathf.SmoothDamp(rigidbody.velocity.x, 0, ref walkDeaccelerationVolx, walkDeacceleration);
            myVector.z = Mathf.SmoothDamp(rigidbody.velocity.z, 0, ref walkDeaccelerationVolz, walkDeacceleration);
            myVector = rigidbody.velocity;
        }

        transform.rotation = Quaternion.Euler(0, camera.GetComponent<MouseLookScript>().currentYRotation, 0);

        if(grounded)
            rigidbody.AddRelativeForce(Input.GetAxis("Horizontal") * walkAcceleration * Time.deltaTime, 0, Input.GetAxis("Vertical") * walkAcceleration * Time.deltaTime);
        else
            rigidbody.AddRelativeForce(Input.GetAxis("Horizontal") * walkAcceleration * walkAccelAirRatio * Time.deltaTime, 0, Input.GetAxis("Vertical") * walkAcceleration * walkAccelAirRatio * Time.deltaTime);


        if (Input.GetButtonDown("Jump")&&grounded)
        {
            rigidbody.AddForce(0, jumpVelocity, 0);
        }
    }

    private void OnCollisionStay(Collision collision)
    {
        foreach(ContactPoint contact in collision.contacts)
        {
            if (Vector3.Angle(contact.normal, Vector3.up) < maxSlope)
                grounded = true;
        }
    }

    private void OnCollisionExit(Collision collision)
    {
        grounded = false;
    }
}

Think carefully about line 45.

That’s what it means to write code at 4 in the morning, not sleeping a day:eyes: Thanks again, I’m sorry for the time taken))