Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Sideways movement is quicker than forward and back when adding force to rigidbody.

Discussion in 'Physics' started by frogblue01, Nov 12, 2022.

  1. frogblue01

    frogblue01

    Joined:
    Mar 27, 2020
    Posts:
    2
    Hello, I am a new unity user.

    My script is very basic but the premises is that when applying a force to a sphere with a rigidbody to get it to roll around on the ground the sideways movements (a and d) are way more sensitive and faster than the forward and backwards movements (w and s). I know that I can change the speed but I only want one float to control speed.

    code screenshot.png
     
  2. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    First tip, post your code in code tags (looks like less than, greater than signs on the little html menu in your post editing panel). This way people looking at your code can just copy and paste it.

    Here is a simple solution to your problem (for a 1kg rb try a rollForce of 50 N):

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BasicMove : MonoBehaviour
    6. {
    7.     public float rollForce = 1f;
    8.     public Rigidbody rb;
    9.  
    10.     private Vector3 inputVectorNorm = Vector3.zero;
    11.  
    12.     void Update()
    13.     {
    14.         Vector3 inputVector = Vector3.zero;
    15.         if (Input.GetKey("d")) inputVector.x += 1;
    16.         if (Input.GetKey("a")) inputVector.x -= 1;
    17.         if (Input.GetKey("w")) inputVector.z += 1;
    18.         if (Input.GetKey("s")) inputVector.z -= 1;
    19.  
    20.         inputVectorNorm = inputVector.normalized;
    21.     }
    22.  
    23.     void FixedUpdate()
    24.     {
    25.         Vector3 appliedForce = inputVectorNorm * rollForce * Time.deltaTime;
    26.         rb.AddForce(appliedForce);
    27.     }
    28. }
    I have kept this as close to your format as I can to reduce confusion. Reasons:

    1. Generally, input is captured at the frame rate (Update) frequency (this isn't completely true [axis data], but that is not important here). So grab your user input in Update().

    2. Give thought to your variable names, speed and force are not the same thing and misnaming them will cause you confusion later.

    3. Apply your forces in FixedUpdate as you were. FixedUpdate runs before each physics solution, so you want to keep your physics actions aligned with the physics solver.

    4. Why does it go faster diagonally. If you draw a right angled triangle with the two perpendicular sides both 1 cm long, you will see that the hypotenuse is about 1.4 cm long. If you imagine your x and z forces are both 1 N, then you can see you are applying a total of 1.4 N diagonally. There are many solutions to this, the most simple is to capture the input vector and normalize it - this just means scaling the vector until its size (magnitude) is 1.

    5. *Answers your posted question* Be careful of doing too much in one step: Take a look at your line:
    rb.AddForce( rollspeed, 0, 0 * Time.deltaTime );

    Here you are scaling the z component (which is zero) by Time.deltaTime, but the rollspeed component is not scaled, you would have needed an extra set of brackets to make that work (i.e. scale the whole vector).

    Additional notes:
    Normalizing a vector is quite crude. The next step would be to use Vector3.ClampMagnitude to allow values between 0 and 1, but you will also find more sophisticated approaches online that allow you to have a true input circle if you wish.

    Make sure you understand variable scope and how to use [SerializeField] to expose private variables to the inspector. It's best practice to keep your public variables to a minimum.

    If you haven't already, have a look at the "new" input system: It looks more complicated and quite daunting, but it gives you a more robust, cross-platform friendly interface. There are lots of online tutorials for it. I agree that for posting quick problem replicators like you have here, the old system is more concise and self-contained, so nothing wrong with using it for forum demos.
     
    Last edited: Nov 12, 2022
  3. frogblue01

    frogblue01

    Joined:
    Mar 27, 2020
    Posts:
    2
    Thank you for the response and the advice.
     
  4. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,428
    There's a severe flaw in both code snippets. Never use Time.deltaTime or Time.fixedDeltaTime in the calculation of a force. If delta time changes, for example by modifying the physics update rate, then the calculated forces (and the behavior) will be radically different.

    Forces are time-independent magnitudes. You apply a given force in N (Newton) to the rigidbody. Once you've applied the force, the physics does the corresponding calculations along time (deltaTime) to get the updated velocities and positions.

    In your code, if removing deltaTime gives too large forces, then simply reduce the values for rollSpeed/rollForce.
     
    AlTheSlacker likes this.
  5. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    I would agree with this normally, but as the initial controller appears to try to achieve a constant acceleration whilst the key is held down, scaling by Time.deltaTime allows the ball to achieve this independent of the physics time step. I appreciate that this could also be achieved by setting a ForceMode to get that acceleration, but that seemed an additional complication to explain. Perhaps calling the the rollForce variable rollForcePerSecond would be better.
     
  6. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,428
    No, this is incorrect. What "scale by Time.deltaTime" does in that case is just multiplying the force by the number 0.02. If the physics time step changes to 0.01 then it will multiply the force by 0.01 so the resulting acceleration will be half of the original acceleration. Time.deltaTime is not making the acceleration "time step independent", but "totally timestep dependent" instead.
     
    bigy likes this.
  7. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    Sorry, Edy is completely correct, I was forgetting that the affect of the duration of the applied force is inherently part of the physics solver calculation, so to multiply by it externally would be completely wrong. As Edy says, remove the "* Time.deltaTime" and scale your rollForce accordingly.
     
    tjmaul and Edy like this.