Moving a RigidBody at a constant speed?

I’d like to move a RigidBody at a constant speed. Normally, I would use something like this to move the RB:

function FixedUpdate () {
  rigidbody.AddRelativeForce (Vector3.forward * 10);
}

But unfortunately this causes the RB to accelerate. My thought was to edit the script so that when the “target speed” is reached the RB’s drag increases, thus slowing it down. Surely there’s a better way but I just can’t think of it. :slight_smile: Anyone have any better ideas?

how about this:

function FixedUpdate () {
if (Input.GetButtonDown ("Jump")) {
rigidbody.velocity = Vector3(0,10,0);
}
}

Pulled this from the scripting reference

2 Likes

Sorry to be kinda off topic, but I’m kinda new to scripting and I was wondering what exactly the FixedUpdate function does.

I hope I explain this correctly, function Update() does an update every frame. The problem is that computers run at different frame rates depending on the video card on that particular computer, the load on the processor etc. This is fine for detecting button inputs and cycling through functions etc. No one will notice the difference. It’s not fine for running physics simulations which depend on a fixed time frame for each update. Thus function FixedUpdate(). Whenever you run a physics based sim of any kind, you put it inside FixedUpdate (). This would include AddForce, Velocity, gravity etc. Otherwise, you could get a lot of variation in how things move and interact on screen depending on what computer the sim is running on. Basically, FixedUpdate() puts the updates on a universal clock that’s the same for all computers.

Now, why not run everything in FixedUpdate()? That’s a question I can’t answer. Hopefully one of the Unity gurus can kick in here and clarify why it’s not used for everything. If I were to guess, I’d think that FixedUpdate() probably eats up more processor time and isn’t as efficient as Update() for routine tasks. It’s probably not as fast because it’s constrained to cycle at a fixed rate rather than speeding up when more processor power is available… Update() probably cycles through code at a faster rate in most cases. But that’s just my speculation.

1 Like

Ok. Thanks that helped.

And, by the way, this is the same reason you use Time.deltaTime for rotation and translation. It puts everything on a fixed clock so that you won’t get something spinning fast on a newer, faster computer and super slow on a dinosaur.:smile:

Are you trying to move an object forward on it’s z axis?

:slight_smile:
Basic Newtonian physics; constant force results constant accelaration, zero force results constant velocity.

2 Likes

You’re adding a force to your rigidbody at the physics framerate. You have a rocket engine, and it’s turned on. Like the above poster said, constant force equates to constant acceleration.

It’s also not framerate independent, as you’re not multiplying the force by the frame delta. This means your object will continue to accelerate, and at different speeds on various computers.

You have the right idea with drag, but do it the opposite way. Apply a force necessary (once) to move your rigidbody at the desired speed, and turn drag off. That way it will continue to move at that velocity until it slams into something or you increase the drag.

The question you asked though, was how to move a rigidbody at a particular speed. Not how to accelerate it to a particular speed. Your rigidbody will move to it’s desired speed instantly, which I’m assuming is what you want.

How about:

rigidbody.AddRelativeForce (Vector3.forward * 10 - rigidbody.velocity);
6 Likes

@MitchStan - That’s what I’m looking for! Sorry that my question wasn’t very clear, but the reason I didn’t want to just use rigidbody.velocity is because it causes an instantaneous change in speed to whatever you’ve set velocity to. Mitch’s solution, in a single line of code, does what I had to use about a dozen lines of code to achieve using force + drag. Nicely done Mitch, thanks!

Edit - Unfortunately, the problem with using this is that it is called every frame and consequently has a huge hit on framerates. Back to the drawing board! :wink:

My programming skills are limited but I am glad my suggestion almost helped. Any way to launch a coroutine to check the velocity every frame and only call rigidbody.AddRelativeForce when needed?

@Quietus, et al - Right, constant force results in acceleration and zero force results in constant velocity if there is zero drag. My apologies for not mentioning it in my original post, but this rigidbody has drag.

@MitchStan - That’s sort of the direction I’m going at the moment and so far it’s resulted in a 30-50% performance boost. Funny how just a couple of lines of code can make such a huge difference.

Thanks again everyone! :slight_smile:

Also – I think ForceMode.VelocityChange might be helpful to you.

Thanks Mitch, I hadn’t looked at that. “VelocityChange” probably won’t work for this particular situation, but it’s worth a read for future reference.

Have you tried using Mathf.Clamp to simply clamp the max velocity? Just let you object accelerate until it reaches the limit you set. Just a thought. Haven’t had time to try it.

I always just did this, never really had problems with it; I don’t know if it would be considered newbish but it works for me:

maxSpeed : float = 10.0;
accel : float = 3.0;

function FixedUpdate () {
    if(rigidbody.velocity.magnitude <= maxSpeed)
        rigidbody.AddRelativeForce(Vector3.forward*accel);
}

As you’ve discovered, keeping a rigidbody at a constant speed is a control problem more than anything else. You might find a PID controller useful here. This measures an actual value (say, speed) and compares it to a desired setpoint. The output of the controller is a correction value based on the error between the actual value and the setpoint. The controller itself is very lightweight, so you could update it each frame but only apply the correction value (as a force) when it gets beyond a certain size.

@legend411 - Thanks, that’s very similar to one method I tried.

@andeeee - Ah, yes, a PID controller. I had forgotten about this, thanks for reminding me about this nifty little tool. Might be a good idea to put it on the Wiki as if you hadn’t reminded me of this I would have never found it. :wink:

I was able to solve this problem by giving the RigidBody a Drag Coefficient of 1 and then just giving it constant full acceleration to offset the drag.