- Home /
(C#) Accelerating Player Based On Distance
Hello, I've been stuck working on this code for a few days now and I've made some progress but am totally stumped.
The scenario: A direction is pressed and the player accelerates linearly from 0 to a speed of lets say 3u/s and hits that speed within 0.5 units distance. The time it takes to accelerate is irrelevant.
I understand that the first thing i have to do is calculate the acceleration, which i've found multiple contradicting formulas for, and then increment the player's position based on that acceleration. Would I also have to calculate how long that would take in order to move the player properly? I've looked extensively into lerps and simply can't figure out a solution. Any help is welcome at this point. Thank you!
Answer by Eno-Khaon · Nov 30, 2018 at 10:54 AM
This is where a good reference point can really come in handy.
By a typical acceleration formula, you're taking the current speed, the target speed, and the time spent accelerating between those two speeds. With that information, you can determine the distance traveled and the rate of acceleration to reach that point.
This is done using the formulas:
tgtSpeed-curSpeed/time = acceleration
(avgSpeed/2)*time = distance
Since you know the distance, however, let's take this equation and work backwards, shall we?
distance/avgSpeed = time
Yep, time still winds up being a valuable factor in this. But since the time can be determined by reversing the speed-to-distance equation, you can use that to turn it back around and calculate the acceleration rate (force) to apply to reach the desired speed.
public static float AccelerateToTarget(float currentSpeed, float targetSpeed, float distance)
{
float averageSpeed = (currentSpeed + targetSpeed) * 0.5f;
float time = distance / averageSpeed;
float speedDifference = targetSpeed - currentSpeed;
float acceleration = speedDifference / time;
return acceleration;
}
float forceToAdd;
void Start()
{
Rigidbody rb = GetComponent<Rigidbody>();
// Example call using your values
forceToAdd = AccelerateToTarget(rb.velocity.magnitude, 3.0f, 0.5f);
}
void FixedUpdate()
{
rb.AddForce(transform.forward * forceToAdd);
}
Granted, this example won't stop accelerating after it reaches that speed after that time, but it will reach the target speed of 3u/s upon traveling 0.5 units (not counting applicable approximation errors and friction).
Answer by 1337keegan · Nov 30, 2018 at 04:37 PM
That's excellent, thank you! However is there a way to do this positionally rather than through force? my object isn't a rigidbody, it's a 2D sprite and I would like to manipulate it through transform.position if at all possible.
Position is calculated by the physics engine(s) about like this:
// Written on a 2D basis
void FixedUpdate()
{
Vector2 velocityPerFrame = lastFrameVelocity + (acceleration * Time.fixedDeltaTime);
Vector2 positionPerFrame += velocityPerFrame * Time.fixedDeltaTime;
}
With that in $$anonymous$$d, that's also the general means of replacement. The AccelerateToTarget() example I gave (when multiplied by a normalized movement Vector) would be the force to add per frame (multiplied by Time.deltaTime or the like) to the current velocity.
You may also want to take a look at the answer @Bunny83 gave to this question to help smooth out the acceleration applied.