- Home /
Why does using a temporary variable break rigidbody?
So, this is kind of an odd situation; I have two scripts attached to a rigidbody. One script will apply a horizontal force when the player presses a button:
// Apply a force in a direction.
rigidbody.AddForce(dir * power, ForceMode.Impulse);
And another has logic for limiting the velocity of the rigidbody:
Vector3 tempVelocity = rigidbody.velocity;
if(maxVelocitySq > 0.0f && tempVelocity.sqrMagnitude > maxVelocitySq)
{
tempVelocity *= slowdownRate;
}
rigidbody.velocity = tempVelocity;
However, when I run the game, the horizontal force doesn't work. I thought that there might be some sort of conflict or overwriting of the rigidbody's velocity force based on the update order of these two scripts, but then I found that I could fix the problem by NOT using a temporary variable in the second script:
// If velocity is too high, apply a slowdown.
if(maxVelocitySq > 0.0f && rigidbody.velocity.sqrMagnitude > maxVelocitySq)
{
rigidbody.velocity *= slowdownRate;
}
And that second version works fine.
My question, then: why would using a temporary variable break the AddForce line in the first script? Does Unity execute physics updates concurrently on different threads, so using a temp variable might overwrite some data? Is there something wrong with using a temp variable? Or is it a bug that rigidbodies would behave this way? I'd note that I'm working on an iOS/Android title, but I only ever see this behavior in the editor.
strange indeed... is it more convenient to have this operating in two separate scripts? have you tried combining this code into one script? i got nothin here, that seems like a bug.
This is reproducible? That is, if you undo the change the problem reoccurs? And this code is exactly as it is in your project? You havn't 'simplified' anything for the post?
Yeah, it seems reproducible, currently using 4.1.2f1. When I use a temporary variable, I don't see other forces applying to the object as I'd expect. Swap to not using a temp variable, and it seems fine. If nothing seems out of place, I can submit a bug report and see if Unity can find any issues.
can we get an entire script that displays the problem. It could be a problem with order of operation.
Sure; basically, I've got a Dasher class with a public method, Dash, which is called from FixedUpdate in response to an input event (such as a swipe):
public class Dasher : $$anonymous$$onoBehaviour
{
[SerializeField]
private float power = 100.0f;
public void Dash(Vector2 direction)
{
// Apply a force in a direction.
rigidbody.AddForce(direction.normalized * power, Force$$anonymous$$ode.Impulse);
}
}
Then, I have a second script, called PhysicsObject, which does some velocity limiting in FixedUpdate:
public class PhysicsObject : $$anonymous$$onoBehaviour
{
// $$anonymous$$aximum velocity of physics object.
[SerializeField]
private float maxVelocity = 0.0f;
private float maxVelocitySq = 0.0f;
// If exceeding max velocity, slow down by this percent.
[SerializeField]
private float slowdownRate = 0.9f;
// A maximum velocity for falling.
[SerializeField]
private float maxFallVelocity = -8.0f;
private void Awake()
{
maxVelocitySq = maxVelocity * maxVelocity;
}
private void FixedUpdate()
{
if(!rigidbody.is$$anonymous$$inematic)
{
Vector3 velocity = rigidbody.velocity;
// If velocity is too high, apply a slowdown.
if(maxVelocitySq > 0.0f && velocity.sqr$$anonymous$$agnitude > maxVelocitySq)
{
velocity *= slowdownRate;
}
// Limit the fall velocity.
if(maxFallVelocity != 0.0f)
{
velocity.z = $$anonymous$$athf.Clamp(velocity.z, maxFallVelocity, $$anonymous$$athf.Infinity);
}
rigidbody.velocity = velocity;
}
}
}
In that second script, things work fine if I don't use that temp variable, but I also don't know how I could limit Z velocity like that without using a temp variable. So far, I've only seen this behavior in the editor, and not entirely consistently. It feels like an execution order issue, but I have tried to explicitly order the scripts using $$anonymous$$ono$$anonymous$$anager, but it doesn't seem to make a difference.
Answer by kromenak · Jun 11, 2013 at 07:40 PM
So, I never really found an answer to why a temporary variable would cause such unexpected physics issues. However, I suppose a valid solution to temporary variables breaking physics is to not use a temporary variable:
// Limit the player's fall velocity.
if(rigidbody.velocity.z < maxFallVelocity)
{
float diff = rigidbody.velocity.z - maxFallVelocity;
Vector3 force = new Vector3(0.0f, 0.0f, -diff);
rigidbody.AddForce(force, ForceMode.VelocityChange);
}
This seems to do the trick by calculating an opposing force on the player and applying it using good old "AddForce". Note that the game I'm working on has gravity on the Z-axis (due to nav-mesh limitations), so you'd probably want to change those Zs to Ys if you copy this code.