Skip to main content
Created a separate question as per advice https://gamedev.stackexchange.com/questions/186534/how-to-mitigate-when-applying-horizontal-force-to-a-rigidbody-seems-to-overpower
Source Link
MrPlow
  • 337
  • 2
  • 18

EDIT: Reading the answer DMGregory linked I know understand why setting the velocity directly is not advisable, but now I have some new questions:

  1. Is it generally advisable to avoid instant force modes like Impulse and Velocity when it comes to things like character movement? I'm assuming VelocityChange functions nearly exactly like setting velocity directly. Am I right?

  2. I've started testing movement using the example code in DMGregory's answer of making a body accelerate to a target velocity

    private void FixedUpdate()
    {
        Vector2 input = GetInput();
    
        if (Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon)
        {
            Vector3 desiredVelocity = new Vector3(input.x * speed, 0f, input.y * speed);            
    
            Vector3 delta = desiredVelocity - body.velocity;
            Vector3 acceleration = delta / Time.deltaTime;
    
            if (acceleration.sqrMagnitude > maxAccel * maxAccel)
            {
                acceleration = acceleration.normalized * maxAccel;
            }            
    
            body.AddForce(acceleration, ForceMode.Acceleration);
        }
    }
    

and I've encountered the following curious behavior: https://imgur.com/snGyVYK When moving the body by applying force, the body seems to levitate as if gravity is not being applied. It actually is being applied but it seems as if the force being applied to the body is overriding the force of gravity because as soon as I let go of the movement keys the body suddenly drops. I am not applying any force on the y axis so I'm not sure what exactly is at play here. What is going on here and what can I do to mitigate this behavior?

EDIT: Reading the answer DMGregory linked I know understand why setting the velocity directly is not advisable, but now I have some new questions:

  1. Is it generally advisable to avoid instant force modes like Impulse and Velocity when it comes to things like character movement? I'm assuming VelocityChange functions nearly exactly like setting velocity directly. Am I right?

  2. I've started testing movement using the example code in DMGregory's answer of making a body accelerate to a target velocity

    private void FixedUpdate()
    {
        Vector2 input = GetInput();
    
        if (Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon)
        {
            Vector3 desiredVelocity = new Vector3(input.x * speed, 0f, input.y * speed);            
    
            Vector3 delta = desiredVelocity - body.velocity;
            Vector3 acceleration = delta / Time.deltaTime;
    
            if (acceleration.sqrMagnitude > maxAccel * maxAccel)
            {
                acceleration = acceleration.normalized * maxAccel;
            }            
    
            body.AddForce(acceleration, ForceMode.Acceleration);
        }
    }
    

and I've encountered the following curious behavior: https://imgur.com/snGyVYK When moving the body by applying force, the body seems to levitate as if gravity is not being applied. It actually is being applied but it seems as if the force being applied to the body is overriding the force of gravity because as soon as I let go of the movement keys the body suddenly drops. I am not applying any force on the y axis so I'm not sure what exactly is at play here. What is going on here and what can I do to mitigate this behavior?

added 1804 characters in body
Source Link
MrPlow
  • 337
  • 2
  • 18

EDIT: Reading the answer DMGregory linked I know understand why setting the velocity directly is not advisable, but now I have some new questions:

  1. Is it generally advisable to avoid instant force modes like Impulse and Velocity when it comes to things like character movement? I'm assuming VelocityChange functions nearly exactly like setting velocity directly. Am I right?

  2. I've started testing movement using the example code in DMGregory's answer of making a body accelerate to a target velocity

    private void FixedUpdate()
    {
        Vector2 input = GetInput();
    
        if (Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon)
        {
            Vector3 desiredVelocity = new Vector3(input.x * speed, 0f, input.y * speed);            
    
            Vector3 delta = desiredVelocity - body.velocity;
            Vector3 acceleration = delta / Time.deltaTime;
    
            if (acceleration.sqrMagnitude > maxAccel * maxAccel)
            {
                acceleration = acceleration.normalized * maxAccel;
            }            
    
            body.AddForce(acceleration, ForceMode.Acceleration);
        }
    }
    

and I've encountered the following curious behavior: https://imgur.com/snGyVYK When moving the body by applying force, the body seems to levitate as if gravity is not being applied. It actually is being applied but it seems as if the force being applied to the body is overriding the force of gravity because as soon as I let go of the movement keys the body suddenly drops. I am not applying any force on the y axis so I'm not sure what exactly is at play here. What is going on here and what can I do to mitigate this behavior?

EDIT: Reading the answer DMGregory linked I know understand why setting the velocity directly is not advisable, but now I have some new questions:

  1. Is it generally advisable to avoid instant force modes like Impulse and Velocity when it comes to things like character movement? I'm assuming VelocityChange functions nearly exactly like setting velocity directly. Am I right?

  2. I've started testing movement using the example code in DMGregory's answer of making a body accelerate to a target velocity

    private void FixedUpdate()
    {
        Vector2 input = GetInput();
    
        if (Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon)
        {
            Vector3 desiredVelocity = new Vector3(input.x * speed, 0f, input.y * speed);            
    
            Vector3 delta = desiredVelocity - body.velocity;
            Vector3 acceleration = delta / Time.deltaTime;
    
            if (acceleration.sqrMagnitude > maxAccel * maxAccel)
            {
                acceleration = acceleration.normalized * maxAccel;
            }            
    
            body.AddForce(acceleration, ForceMode.Acceleration);
        }
    }
    

and I've encountered the following curious behavior: https://imgur.com/snGyVYK When moving the body by applying force, the body seems to levitate as if gravity is not being applied. It actually is being applied but it seems as if the force being applied to the body is overriding the force of gravity because as soon as I let go of the movement keys the body suddenly drops. I am not applying any force on the y axis so I'm not sure what exactly is at play here. What is going on here and what can I do to mitigate this behavior?

Source Link
MrPlow
  • 337
  • 2
  • 18

What are the dangers of setting rigidbody velocity directly for movement and what are the alternatives

I'm playing around with Unity, trying to make a neat 3rd person platformer movement system using rigidbodies so that I may in the future implement things like pushing boxes/physics objects, grappling hooks, etc... as well as I'm not really knowledgeable in terms of math and physics to be able to code them from scratch using CharacterController

What I've done is I've implemented some basic movement by setting velocity directly

Vector2 input = GetInput();
bool hasInput = Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon;
bool isDashing = dashCounter > 0f;
if (hasInput && !isDashing)
{
    Vector3 direction = GetDirection(); // get camera direction scaled by forward & right vectors
    transform.localRotation = Quaternion.LookRotation(direction);

    UpdateTargetSpeed(input); // update target speed based on movement direction
    Vector3 movementVector = new Vector3(input.x * TargetSpeed, 0f, input.y * TargetSpeed); // add speed to input vector
    movementVector = transform.localRotation * movementVector; // rotate the vector to where the character is facing
    movementVector = Vector3.ClampMagnitude(movementVector, TargetSpeed); // clamp magnitude to avoid faster speed on diagonals            

    body.velocity = new Vector3(movementVector.x, Velocity.y, movementVector.z);
}

And I'm also projecting velocity on ground normal for slopes so that the character doesn't fly off when moving down slopes

if (wasPreviouslyGrounded && !jumping && groundCheck.CanStick)
{
    float slopeAngle = Mathf.Abs(Vector3.Angle(groundCheck.StickyContactNormal, Vector3.up));                
    if (slopeAngle < 85f)
    {
        body.velocity = Vector3.ProjectOnPlane(Velocity, groundCheck.StickyContactNormal);
    }
}

I have implemented jumping and dashing using AddForce

body.AddForce(0f, movementSettings.JumpForce, 0f, ForceMode.Impulse);

This all works okay but everywhere I looked people are always claiming that setting velocity directly is a bad practice and should be avoided. I've seen suggestions to use AddForce instead, but I haven't been able to get the same movement with it, no matter which force mode I used. I am also lost on how to control the amount of force I'm giving to the body during continuous movement. The thing I did is to check the magnitude of body's current velocity and if it's at or above the target speed then forgo applying the force but that just makes the body continuously accelerate and decelerate giving off jittery movement

if (body.velocity.sqrMagnitude < TargetSpeed * TargetSpeed)
{
    body.AddForce(force, ForceMode.VelocityChange);
}

Can anyone ELI5 me the answers to the following questions:

  1. Why exactly is setting velocity directly a "bad practice"?
  2. What is the preferred alternative?
  3. How can I get snappy and responsive movement without setting the velocity directly?
  4. How can I accomplish sticking to the ground when going down slopes without projecting and setting the velocity directly?