My rigidbody script for moving, sprinting and jumping doesn't work besides the movement,Pleease help

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

public class PlayerMovement : MonoBehaviour {

public float speed;
public float sprintModifier;
public float jumpForce;
public Transform groundCheck;
public LayerMask ground;

private Rigidbody rb;

private void Start() {
rb = GetComponent();
}

void FixedUpdate() {
//Axis
float x = Input.GetAxisRaw(“Horizontal”);
float z = Input.GetAxisRaw(“Vertical”);

//Controls
bool sprinting = Input.GetKey(KeyCode.LeftShift);
bool jumping = Input.GetKeyDown(KeyCode.Space);

//States
bool isGrounded = Physics.Raycast(groundCheck.position, Vector3.down, 0.1f, ground);
bool isJumping = jumping && isGrounded;
bool isSprinting = sprinting && z > 0 && !isJumping && isGrounded;

//Jumping
if (isJumping) {
rb.AddForce(Vector3.up * jumpForce);
}

//Movement
Vector3 direction = new Vector3(x, 0, z);
direction.Normalize();

float adjustedSpeed = speed;
if (isSprinting) adjustedSpeed *= sprintModifier;

Vector3 targetVelocity = transform.TransformDirection(direction) * adjustedSpeed * Time.deltaTime;
targetVelocity.y = rb.velocity.y;
rb.velocity = targetVelocity;
}
}

First, use Code tags to post code. It’s much more readable.

I think the issue with your code is that you’re mixing two fairly incompatible approaches to working with rigidbodies: Adding forces, and setting velocity. The last thing you’re doing here is setting the rigidbody’s velocity, which will essentially cause any other AddForce calls to be overwritten by the new velocity.

Be careful setting velocity. With your movement code the way it is, it means that if some other object collides with your player, the player won’t realistically respond to the collision force. You’re basically manually setting velocity every frame, so the character won’t behave realistically.

Another option is to use AddForce for movement. You’ll probably need to reduce the amount of force applied depending on current speed, or you’ll get endless acceleration.

Can you give me and example or how should the code be writen?

Pretty much what you have now, where you’re figuring our the velocity vector. However, instead of using that to set the velocity, use it to call AddForce on the rigidbody. You’ll need to multiply the direction vector by some constant to control how much force to apply.

When you do that, you’ll notice that you keep accelerating. So you’ll need something to reduce the force as the velocity increases. You could do something like this:

var speedFactor = (MaxSpeed -  rb.velocity.magnitude) / MaxSpeed;
rb.AddForce(speedFactor * MovementForceAmount * direction, ForceMode.Impulse);

In this case, MaxSpeed and MovementForceAmount are just two “float” properties I’ve created here which you’ll need to assign values to. That’s a fairly easy way to decrease the force as the speed goes up. There are better ways to do this, such as using the Dot product to compute the speed in the actual direction you’re facing, but that should get you started.

Another small detail: Using deltaTime within FixedUpdate isn’t really needed. It will always have the same very every time, unlike if you use deltaTime within Update. I personally don’t use it within FixedUpdate.

But it still doesn’t solve the jumping problem.

There isn’t a “jumping” problem. Jumping should be fine, as long as you’re adding enough force. Like I said earlier, because you’re manually setting velocity after calling AddForce, it’s as though you never called AddForce.

Is this good?

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

public class PlayerMovement : MonoBehaviour {
public float speed;
public float jumpForce;
public float sprintModifier;
public float MaxSpeed;
public float MovementForceAmount;

public Transform groundCheck;
public LayerMask ground;

private Rigidbody rb;

private void Start() {
rb = GetComponent();
}

void FixedUpdate() {
//Axis
float x = Input.GetAxisRaw(“Horizontal”);
float z = Input.GetAxisRaw(“Vertical”);

//Controls
bool jumping = Input.GetKeyDown(KeyCode.Space);
bool sprinting = Input.GetKey(KeyCode.LeftShift);

//States
bool isGrounded = Physics.Raycast(groundCheck.position, Vector3.down, 0.1f, ground);
bool isJumping = jumping;
bool isSprinting = sprinting;

if (isJumping) {
rb.AddForce(Vector3.up * jumpForce);
}

//Movement
Vector3 direction = new Vector3(x, 0, z);
direction.Normalize();

float adjustedSpeed = speed;
if (isSprinting) adjustedSpeed *= sprintModifier;

var speedFactor = (MaxSpeed - rb.velocity.magnitude) / MaxSpeed;
rb.AddForce(speedFactor * MovementForceAmount * direction, ForceMode.Impulse);

Vector3 targetVelocity = transform.TransformDirection(direction) * adjustedSpeed * Time.deltaTime;
targetVelocity.y = rb.velocity.y;
rb.velocity = targetVelocity;
}
}

The last line of code you have there is still setting the velocity of the rigidbody. Did you just forget to remove/comment it out?

Anyway, you’ll need to tell me if it works. I can maybe spot mistakes, but you’ll need to run it and say whether it works or not.

Hey, my man, that’s three posts in a row now that you posted code without tags.

It’s right there above the text box.

I, and many other people here, will not even look at your code if you don’t use the tags.

Why @dgoyette is even trying to help you still after you’ve ignored his first post twice in a row now about using the tags is beyond me.

They’re really nice I suppose.

If you can be bothered to find the code tags button, maybe others can be bothered to help you.

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

public class PlayerMovement : MonoBehaviour {
    public float speed;
    public float jumpForce;
    public float sprintModifier;
    public float MaxSpeed;
    public float MovementForceAmount;

    public Transform groundCheck;
    public LayerMask ground;

    private Rigidbody rb;

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

    void FixedUpdate() {
        //Axis
        float x = Input.GetAxisRaw("Horizontal");
        float z = Input.GetAxisRaw("Vertical");

        //Controls
        bool jumping = Input.GetKeyDown(KeyCode.Space);
        bool sprinting = Input.GetKey(KeyCode.LeftShift);

        //States
        bool isGrounded = Physics.Raycast(groundCheck.position, Vector3.down, 0.1f, ground);
        bool isJumping = jumping && isGrounded;
        bool isSprinting = sprinting && z > 0;

        if (isJumping) {
            rb.AddForce(Vector3.up * jumpForce);
        }

        //Movement
        Vector3 direction = new Vector3(x, 0, z);
        direction.Normalize();

        float adjustedSpeed = speed;
        if (isSprinting) adjustedSpeed *= sprintModifier;

        Vector3 targetVelocity = transform.TransformDirection(direction) * adjustedSpeed;
       
        var speedFactor = (MaxSpeed -  rb.velocity.magnitude) / MaxSpeed;
        rb.AddForce(speedFactor * MovementForceAmount * direction, ForceMode.Impulse);
       
        targetVelocity.y = rb.velocity.y;

It moves but it does on the axes without changing them to my direction.

1 Like
  1. I would DEFINITELY move all of your bools that you’re using as states out of the fixedupdate and make them public just so you can debug them.

  2. you really should tackle these one at a time, rather than try and do them all at once. It will make it easier to test every case as you add it and keep track of where you are.

That is (for example) :

Do looking.

Then do movement. Then check to see that you can look while moving.

Then do slopes and steps. Then make sure that you can look and move freely of them in all directions.

Then do jumping. Then make sure you can look around while jumping, change direction in the air like you want, jump off of a slope.

Then do dashing. Then make sure you can look around while dashing, change the direction like you want, dash up and down slopes, and have dash work how you like while dashing.

See how each iteration it gets more and more complex?

If you just jump in all at once you are ABSOLUTELY going to lose track of your progress.

And when things break when you add a new functionality, you know where in your code to look.

  1. Don’t make bools for your buttons. Your buttons are already bools and you’re just adding unnecessary code.

  2. Make a two separate vectors for your input and for your movement. Don’t depend on axis gravity to handle your acceleration.

  3. I would seriously consider just scrapping this and starting from scratch. Try Brackey’s tutorial out. It’s missing a few things, like normalizing, but it gives you a GREAT starting point and a lot of this can be applied to a RB controller.

You’re getting axis-aligned movement because you’re just mapping forward and right inputs to world X and Z coordinates. You’ll need to rotate your movement vector to aim in the same direction as your visual direction. So, maybe take your “direction” vector and instead of 0 for the y-component, try passing in your player’s eulerAngle y-component. I’m not 100% sure that works, but that’s the basic idea.

Thanks, both of you, i started from scratch and got your advise @dgoyette and it works.

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

public class PlayerMovement : MonoBehaviour {
    //Other
    private Rigidbody rb;

    public Transform playerCamera;
   
    //Movement
    public float speed;
    public float maxSpeed;
    public bool isGrounded;
    public LayerMask ground;

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

    void FixedUpdate() {
        //Axis
        float x = Input.GetAxisRaw("Horizontal");
        float z = Input.GetAxisRaw("Vertical");

        //How fast the player should move
        var targetVelocity = new Vector3(x, 0, z);
        targetVelocity = transform.TransformDirection(targetVelocity);
        targetVelocity *= speed;

        //Adding force to move the player
        var velocity = rb.velocity;
        var velocityChange = (targetVelocity - velocity);
        velocityChange.x = Mathf.Clamp(velocityChange.x, -maxSpeed, maxSpeed);
        velocityChange.z = Mathf.Clamp(velocityChange.z, -maxSpeed, maxSpeed);
        velocityChange.y = 0;
        GetComponent<Rigidbody>().AddForce(velocityChange, ForceMode.VelocityChange);
    }
}
1 Like

I have a queastion about fall damage:
Should i put the fall damage script in my movement script or in a new one?
And if yes then c

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

public class FallingDamage : MonoBehaviour {

    //public Transform health;
    public float timeInAir;

    // Update is called once per frame
    void Update() {
        //Here we decrease the time in air from 5
        //Grounded is used by Rigidbody controller
        if(!grounded)
            timeInAir -= 1 * Time.deltaTime;
  
        //Increase the time in air to reach 5 each time we're on ground
        if(grounded && timeInAir < 5 && timeInAir > 0)
            timeInAir = 5;
        //Making the player die when it reaches 0
        if(timeInAir <= 0)
        //Debug.Log("You Died!");
        //Or just damage player on a "checkpoint", in this case I use 3
        if(timeInAir == 3 && grounded)
            PlayerHealth -= 30;
    }
}

an I put this code in FixedUpdate ?

It’s a good idea to break things into small, simple scripts, if possible. So that’s fine. Your script has a bit of a problem though, in the 30 damage you’re applying. You’re testing whether timeInAir equals exactly “3”. Given that timeInAir is the sum of a bunch of tiny units of time, it’s almost never going to equal 3 exactly. More likely it would equal 3.0013 or 2.9986, or something near three. Also, line 24 would never be true anyway, since if timeInAir had been three when the player was grounded, you would have changed timeInAir back to 5 on line 19. So, you should try to fix that.

Using air time to determine fall damage is probably fine in simple games. But I think it’s probably a bad approach in general, since it limits the kinds of gameplay you can have. Your code says that if the player spends more than 5 seconds in the air, they will die when they land. But what if something was causing them to slowly fall to the ground, like a parachute? With your code, they’d still die after falling 5 seconds with a parachute. And what if you want to add a double-jump feature, increasing the time spent in the air? Using that might cause you to be in the air longer than 5 seconds.

Anyway, I’d recommend basing the death/damage not on total air time. Instead, I’d probably base it on velocity when landing, or the collision force when landing. That information is provided in the Collision object given to OnCollisionEnter, which your grounded script could be using.

I really don’t know how to apply the damage then i hit the ground.

public bool falling;
public bool takeDamage;
public float minDamageAmount;

void FixedUpdate() {
        //updating the velocity
        if (falling) {
            takeDamage = (rb.velocity.y * gravity * minDamageAmount);
            grounded = false;
        }
}

Usually falling damage is based either on the velocity at the time of impact, or the ‘impulse’ force of the collision. Both can be found on the Collision object obtained from OnCollisionEnter. I would expect that a “fall damage” script would contain an OnCollisionEnter method which would determine the damage based on the force of relativeVelocity of the collision.

Another approach would be to compare the current velocity to the velocity from the previous frame, and damage the player if the change in velocity is great enough. The disadvantage to that approach is that suddenly getting tossed quickly upward might trigger the damage.

        if (falling) {
            rb.velocity = new Vector3(x, velocity.y, z) * gravity;
            grounded = false;
        }

Is this good for increasing my velocity on the axis Y?