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 Code being overwritten when having multiple Rigidbody.MovePosition()

Discussion in 'Scripting' started by NewSystemGames, Jun 12, 2023.

  1. NewSystemGames

    NewSystemGames

    Joined:
    May 23, 2017
    Posts:
    303
    Hi all,

    I have written the below script that moves attempts to move a rigidbody on the x, y and z axis, however, it's only moving the object on the z axis (last line) except when I have the 1f value on the z at 0f, so the code is being overwritten by the last line for some reason... how can I rewrite it so it runs all 3 lines simultaneously?

    Code (CSharp):
    1.         if (x.input != 0.0f)
    2.             rb.MovePosition(transform.position + transform.right * 1f * x.speed * Time.deltaTime);
    3.  
    4.         if (y.input != 0.0f)
    5.             rb.MovePosition(transform.position + transform.up * 1f * y.speed * Time.deltaTime);
    6.  
    7.         if (z.input != 0.0f)
    8.             rb.MovePosition(transform.position + transform.forward * 1f * z.speed * Time.deltaTime);
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Because MovePosition works this way. You call it and during the next simulation step, the move will happen. The above won't queue three moves, it'll do the last one you asked for in the next simulation step.

    You need to calculate the position you want to move to and call this once.

    Physics doesn't run per-frame so if you're doing this per-frame, there can be many frames before the FixedUpdate call.

    Plenty of information about this online. Look up "FixedUpdate Physics" and how to use MovePosition etc.
     
  3. tomfulghum

    tomfulghum

    Joined:
    May 8, 2017
    Posts:
    69
    This should do what you want. Like Melv said, we first calculate the new position and then call MovePosition once. Note that multiplication with 1 is pointless, it doesn't change the result.

    Code (CSharp):
    1. Vector3 newPosition = transform.position;
    2.  
    3. if (x.input != 0f)
    4.    newPosition += transform.right * x.speed * Time.deltaTime;
    5.    
    6. if (y.input != 0f)
    7.    newPosition += transform.up * y.speed * Time.deltaTime;
    8.    
    9. if (z.input != 0f)
    10.    newPosition += transform.forward * z.speed * Time.deltaTime;
    11.    
    12. rb.MovePosition(newPosition);
     
    Bunny83 and NewSystemGames like this.
  4. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    620
    Code (CSharp):
    1.  
    2. Vector3 wantedOffset = Vector3.zero;
    3. if (x.input != 0.0f) wantedOffset += transform.right * 1f * x.speed;
    4. if (y.input != 0.0f) wantedOffset += transform.up * 1f * y.speed;
    5. if (z.input != 0.0f) wantedOffset += transform.forward * 1f * z.speed;
    6.  
    7. Vector3 wantedPosition = transform.position + wantedOffset * Time.deltaTime;
    8. rb.MovePosition(wantedOffset);
    9.  
    The code should already speak for itself but yea - accumale your values to a local Vector3 first, then call the MovePosition Method once.
    I don't really undestand why you have a speed AND input value, but I don't know how everything else in your code looks like. Tho, I wouldn't compare a float to a value directly, you should use some margin instead, something like
    if(Mathf.Abs(x.input) < 0.01f)
    as float-values tend to produce some weird numbers from time to time (because of precision issues). It usually works with 0, but as this is an input value, I'd definitely add a margin.

    Also I reduced some of the code duplication in my example. I'm a lazy coder, I write as less as possible and when there are changes I want to keep them at the minimum amount of places (in this case, if I want to change deltaTime to e.g. fixedDeltaTime or smoothDeltaTime for some reason, I can do that in one spot instead of 3 now). I guess the
    *1f *
    is for testing, so I left it at each line.
     
    NewSystemGames likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    But again, be careful because doing this per-frame means only the last frame that happened before the next update actually gets processed. The Transform won't be updated until it runs so doing this per-frame is flawed.
     
    NewSystemGames likes this.
  6. NewSystemGames

    NewSystemGames

    Joined:
    May 23, 2017
    Posts:
    303
    Thank you, Input is for the user/ai input which is -1f to 1f and speed is the multiplier so I need them to be seperate values and I only want to run the move code if there is a input from the user.