- Home /
AddForce and Maximum Speed
I'm trying to build an asteroids clone so the player ship can turn regardless of its moving direction. When the player moves forward I want to apply force to the ship, so the perceived effect is like flying in space.
My code right now is:
rigidbody.AddRelativeForce(Input.GetAxis("Vertical") * Vector3.forward * Time.deltaTime);
Generally it works correctly except for one thing, I'd like the ship to have some top speed. If a ship is moving in a given direction, beyond a certain point the force from its afterburner can't move it any faster, right?
At the moment the code above means that the ship can accelerate infinitely. I can't use drag because this is movement in space. If the player doesn't press any key the ship should continue drifting at its current velocity.
Am I misunderstanding the physics involved? Should I be using a different method? Or is the only solution coding myself the mitigation of the applied force?
Answer by amirabiri · Oct 11, 2012 at 06:16 AM
So far there isn't a really good solution to this issue. My particular solution is:
if (Input.GetButton("Vertical"))
rigidbody.AddRelativeForce(Vector3.forward * acceleration * Time.deltaTime);
if (rigidbody.velocity.magnitude > topSpeed)
rigidbody.velocity = rigidbody.velocity.normalized * topSpeed;
However there are shortcomings to this approach so if anyone has a better solution please post it (remember the context is a ship in outer space).
Answer by Judgeking · Nov 20, 2017 at 04:02 AM
Best solution I found gave me this, works perfectly:
public float moveSpeed, maxSpeed;
private Rigidbody rb;
private Vector3 input;
void Start () {
rb = GetComponent<Rigidbody>();
}
void FixedUpdate () {
input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
rb.drag = (moveSpeed / maxSpeed);
rb.AddForce(input * moveSpeed);
}
Answer by DayyanSisson · Sep 03, 2011 at 05:04 PM
I was given this script for my question somewhat like this:
var Speed : float = 50.0;
var maxSpeed : float = 100.0;
var minSpeed : float = 10.0;
var maxAcceleration : float = 30.0;
var currentSpeed : float = 50.0;
function Update()
{
transform.Translate(Vector3.forward * Time.deltaTime * currentSpeed);
if(Input.GetKey("up"))
currentSpeed += maxAcceleration * Time.deltaTime;
else if(Input.GetKey("down"))
currentSpeed-=maxAcceleration * Time.deltaTime;
else if (currentSpeed > Speed){
currentSpeed = currentSpeed;
}
else if (currentSpeed < Speed){
currentSpeed = currentSpeed;
}
else {
currentSpeed += maxAcceleration * Time.deltaTime;
currentSpeed = Mathf.Clamp(currentSpeed, minSpeed, Speed);
}
currentSpeed = Mathf.Clamp(currentSpeed, minSpeed, maxSpeed);
}
There you go. I hope this helps.
Thanks for the answer. Unfortunately this isn't based on AddForce. I'm trying to move a ship in space using the physics engine, and the ship could be facing a different direction than it is travelling at.
Hmm, I think your code has become a bit jumbled. It seems to mostly work, but I get this in the console:
Assets/Scripts/JavaScripts/Rig_Control.js(60,18): BCW0020: WARNING: Assignment made to same expression. Did you mean to assign to something else?
Looking at the code, you have things like "currentSpeed = currentSpeed", which is what it is complaining about, but you also have the if statements set up so that if currentSpeed is either less than or greater than Speed then it equals itself. doesn't that negate itself?
Perhaps it's just some of the variables that are mixed up?
They aren't mixed up, I just wrote it inproperly. I forget the exact method, but what you can do is put a variable called currentSpeedD in update and then write :
currentSpeedD = currentSpeed;
Then, on that line of code, write :
else if (currentSpeed < Speed){
currentSpeed = currentSpeedD;
}
It would work the same, and there would be no error. There's a more efficient way, but I switched to C# since then, so I forget. But this way works too.
Answer by Jonatan Crafoord · Oct 11, 2012 at 09:01 AM
Hi again,
I see the problem with using drag in space... :-p But if that is the case, maybe you can just limit the amount of acceleration you add until it is zero at top speed? For example:
var accelerationMultiplier = 1 - (rigidbody.velocity.magnitude / topSpeed);
if (Input.GetButton("Vertical"))
rigidbody.AddRelativeForce(Vector3.forward * acceleration * accelerationMultiplier * Time.deltaTime);
The multiplier goes from 1 (no speed, 100% acceleration) to 0 (top speed, 0% acceleration) If you want the multiplier to be less pronounced, you can use its square root. That way will still go from 1 to 0, but will make a curve instead of a line.
EDIT: So, this leads to severe issues if we change the directional Vector. We also need the multiplier to take into account if you're trying to go in a different direction from your velocity vector.
// Your normalized thrust vector (the direction you want to go)
var direction : Vector3;
// Sum up your normalized direction with the normalized velocity vector and
// divide by 2 to get a new vector with magnitude 0-1
var sumVector : Vector3 = 0.5 * (direction + rigidbody.velocity.normalized);
// Make a multiplier that goes from 0 (aligned vectors) to 1 (inversed vectors)
var directionMultiplier = 1 - sumVector.magnitude;
// Include it in the accelerationMultiplier
var accelerationMultiplier = (1 - (rigidbody.velocity.magnitude / topSpeed)) * directionMultiplier;
// Apply the force
if (Input.GetButton("Vertical"))
rigidbody.AddRelativeForce(direction * acceleration * accelerationMultiplier * Time.deltaTime);
Try your code the following way: accelerate to top speed in one direction, then turn 90 degrees right and press the thrust key...
Oh, yes... :-p So, we need to keep track of the Vector too then. I'll try to modify my answer in a bit.
I was thinking of a solution with a dot product (game world is 2D). There is also a question of how the solution reacts when the ship is already at a speed higher than its top speed (from impact for example or under a temporary slow effect).
Added a new code attempt. Haven't tried it, and I usually code C#, but hopefully you get the idea behind.
There is probably a cleaner way of doing it. But this solution should actually brake your speed if you're above max. Any speed bonuses or slow effects should probably change the topSpeed value to make it work correctly.
Answer by Jonatan Crafoord · Oct 10, 2012 at 10:10 PM
I was looking for this for a long time as well. Finally found the answer in this forum post: http://forum.unity3d.com/threads/34667-Terminal-Velocity
If your question was answered, please accept, even if was answered by yourself.
$$anonymous$$y particular context is a ship in outer space, where the object preserves it's momentum, therefore I can't use drag.