(C#) Accelerating Player To Max Speed Within Specific 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!

If we’re assuming continuous time, then velocity is the integral of acceleration, and position is the integral of velocity.

If a player starts stationary and accelerates at a constant rate of a, then the velocity as a function of time is v(t) = at, and the position is x(t) = at*t / 2. (Formally, integrals should also have a +C constant term, but our assumption that the player starts with 0 velocity at position 0 at time 0 forces those constants to all be zero. If you want to do this for a case where the starting velocity is something other than 0, it gets more complex.)

You want the position to be some value M (e.g. .5u) at the same time the velocity is some other value N (e.g. 3u/s), we can set

x(t) = att / 2 = M
v(t) = a*t = N

Then we can solve for t by substituting the second equation into the first one

att / 2 = M
(N)*t / 2 = M
t = 2 * M / N

and then we can substitute that back into the second equation to solve for a

at = N
a
(2M/N) = N
a = N^2 / (2
M)

Of course, video games do not have continuous time, they have time that moves forward in discrete steps. So if you just set velocity += a * Time.deltaTime every frame, you’ll get a result that is slightly off from the prediction. (How far off depends on your framerate.) This may or may not be noticeable depending on the parameters of your particular case.

If you want to give a better illusion of continuous time, you could explicitly set the player’s position every frame based on our original equation x(t) = att / 2, with some adjustments at the end when the player reaches the intended peak velocity. However, if you set the player’s position directly, you may get poor interactions with any other physics you have going on; if the player collides with something, or if there are other forces operating on the player at the same time, you could get weird results.

1 Like

Thanks for the response. I’ve found some formulas that seem much simpler than what you provided and just need a bit of help implementing them. What I have is:

A = deltaV / 2d in order to get the acceleration within a set distance
and
deltaT = deltaV / A to calculate how long that would take. (not sure if this is needed, but i have it)

So from what i gather to move the character I would need to loop ‘while(currentSpeed < MaxSpeed)’ and increment my velocity with ‘currentSpeed += acceleration * deltaTime’ but then where i’m iffy is the syntax for using that velocity to set the player’s position.

my guess is something along the lines of:

transform.position += new Vector3 (direction.x * currentSpeed * Time.deltaTime, same thing for y, 0)

but i’m not totally sure.

You don’t want a loop. You want to write something in an Update() function (or possibly one of its cousins like FixedUpdate()) that updates for whatever the current time is in that frame. (Assume the player is currently in the correct position for the previous frame, and then calculate where he should be based on that old position and the amount of time that has passed. If you need more information than that from the previous movement, store it in class variables.)

Also, assuming that the “d” in “A = deltaV / 2d” is supposed to be the distance over which you are accelerating, then simple dimensional analysis is enough to prove that formula is wrong. (Velocity is distance/time, so velocity divided by distance is just 1 / time, but acceleration should be distance / time^2.)

I am not following. I don’t see what’s so bad about having a loop because that still takes time to iterate just like update does? I’ve also found that acceleration equation multiple places online and calculating by hand then calculating time from that acceleration still gives me the exact same answer as online calculators. The equation assumes that your initial velocity is 0 however, so i guess deltaV would just your max speed. The math seems to work?

Regular loops do NOT take time. (That is, “game time” does not pass. Obviously, some amount of time passes in the real world, but that doesn’t matter for your algorithm.)

It’s possible to create a loop that takes time if you use a coroutine with yield statements. You can do that if you prefer.

That just tells you that the calculators you found are that equation, not that the equation is correct. Any answer is going to be the same as itself.

Let’s try working out an example by hand:

IMPORTANT: Since you still haven’t clarified your notation, I am continuing to assume that “d” means the distance you want to accelerate over. If that’s not true, then you haven’t actually told me how this equation works, so all bets are off.

Suppose you want to accelerate to 100 units/sec over 10 units of distance.

Distance = 10 units
Final velocity = 100 units/sec

A = deltaV / 2d
A = 100 / (2*10) = 5

It’ll take (100 / 5) = 20 seconds to reach your final velocity.

If you’re willing to trust my integral, your position at the end of 20 seconds will be

x(t) = att / 2
x(20) = 52020 / 2 = 100*20 / 2 = 1000

You were supposed to accelerate over 10 units, but it actually took you 1000!

If you’re not willing to trust my integral, you can still tell you’re way off like this:

At the end of 1 second, you are going 5 units/sec. Therefore, between 1.0 sec and 2.0 sec, you must move AT LEAST 5 units. (It’ll actually be more than that because you continue accelerating during that second, but there’s no way it’ll be less than 5, because your speed was never lower than 5 during that stretch of time.)

At the end of 2 seconds, you’re going 10 units/sec. Therefore, between 2.0 sec and 3.0 sec, you must move AT LEAST 10 units.

So after just 3 seconds, we’ve already moved OVER 15 units in total, but our velocity is still only 15 units/sec, far below our target final velocity.

Of course, since the dimensional analysis is wrong, you’ll actually get different answers depending on what units you choose. A velocity of 100 units/sec is the same as a velocity of 1.67 units**/minute**, but if you try plugging in that number and solving the problem again, you’ll get a different answer, because the equation doesn’t even have correct dimensions.

I apologise if I came off as rude or aggressive in my last reply, that was not my intention. I seem to have mis-typed the equation I had written down while hastily writing that post, which I agree is most definitely wrong. It was supposed to be:

A = (V2^2 - V1^2) / 2d

where A = acceleration, V2 = final velocity, V1 = initial velocity, and d = distance.

Using your example of 100u/s over 10 units:

A = 100^2 / 20
A = 500u/s

t = 100 / 500
t = 0.2 seconds

which I can then put into your equation:

x(0.2) = 500 * 0.2 * 0.2 / 2
x(0.2) = 10

So the math does end up the same, and I apologise for the mix-up.
I would very much like to see how you would implement the acceleration within the fixedUpdate function though if you don’t mind.

Thank you for the patience.