0
\$\begingroup\$

I am building a game in C# using XNA.

I am currently trying to get a character to always travel to the middle of the map which is located a point (0,0,0). I want the character to accelerate to the middle and then decelerate before it hits the middle so it will come to a stop at (or very close to) the middle.

Rate of acceleration does not change. Velocity is a Vector3 and for the purpose of this i will only worry about the X axis.

What I am trying to work out is at what point should I start decelerating to come to a stop in the middle depending on velocity and position.

I have tried to simplify the following code as much as possible

In My Update Method I basically call two methods

    Move(gameTime);
    HandleAcceleration();

Handle Acceleration is very simple

 this.Transform.TranslateIncrement = this.Velocity;

Move method

protected void Move(GameTime gameTime)
{
    //GetDirection just returns 1 or -1 to accelerate the appropriate direction
    int direction = GetDirection((int)this.Transform.Translation.X);

    //This Is where I have trouble With GetMinDecelerationDistance()
    if (GetDistanceToMiddle() <= GetMinDecelerationDistance())
    {
        //Pass in -direction to decelerate(Accelerate opposite direction)
        Accelerate(gameTime, AxisDirectionType.X, -direction);
    }
    else
    {
        Accelerate(gameTime, AxisDirectionType.X, direction);
    }
}

My Accelerate Method

    VelocityX += (this.acceleration * gameTime.ElapsedGameTime.Milliseconds) * direction;

    this.Velocity = (new Vector3(VelocityX, 0, 0));

The problem I am having is how to implement the GetMinDecelerationDistance() Method. I know I need to do something with the Velocity and the position but I have no Idea what. Keep in mind the acceleration rate is always the same and the middle is at point 0.

Basically my question is how do I implement GetMinDecelerationDistance() given that I know the Velocity and position, Acceleration is constant and I want to stop at point 0.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Considering for now the case where all our movement is in the line joining the target and destination (in 2+ dimensions this becomes much more complicated)...

Let's look at our formulas for position & velocity as functions of time under constant acceleration.

$$\begin{array}{r|l} {p(t) = p_0 + v_0 \cdot t + \frac a 2 \cdot t^2 \\ v(t) = v_0 + a\cdot t }& \begin{align} p(t) &= \text{position at time t} \\ p_0 &= \text{initial position} \\ v(t) &= \text{velocity at time t} \\ v_0 &= \text{initial velocity} \\ a &= \text{constant acceleration} \end{align}\end{array}$$

If we imagine we're starting at the destination point, at rest, and accelerating away as fast as we can, then we can work out the relationship between our position and the velocity we can reach by the time we cross that mark.

$$\begin{array}{l|l} {p(t) = \frac a 2 t^2 \\ p(t) = \frac {a^2 t^2} {2a} \\ p(t) = \frac {\left(at\right)^2} {2a} \\ p(t) = \frac {v(t)^2} {2a} } & { v(t) = a t \\ v(t) = \pm\sqrt{a^2t^2} \\ v(t) = \pm \sqrt{2a \cdot \frac a 2 t^2} \\ v(t) = \pm \sqrt{2a \cdot p(t)}} \end{array}$$

Flipping this around, this gives us our limiting position-velocity - the fastest we can possibly be going at a given distance and still decelerate to a stop as we reach the target.

That lets us partition our position-velocity state space like so:

enter image description here

We can look at our initial position & velocity to determine which of three cases we're in:

  • viable: we can accelerate toward the target for some time \$t_a\$ (possibly zero, if we're right on the curve \$p = \frac {v^2} {2a}\$), then decelerate until we come to a stop exactly on the target.

  • overshoot: we're approaching the target too fast to stop in time. We need to start decelerating immediately, overshoot a little before coming to a stop, continue accelerating back toward the target, and ultimately hit the approach curve from the other side and decelerate again until we come to a rest at the target.

  • wrong way: we need to kill our outward velocity first, then continue accelerating toward the target to hit the approach curve on the near side, like in the viable case.

In each of these cases, we want an initial acceleration for time \$t_1\$, then a final deceleration for time \$t_2\$


If we're in the overshoot (\$v_0 * -sign(p_0) > \sqrt{2a \cdot p_0}\$) or wrong way (\$sign(v_0) = sign(p_0)\$) cases, we first need to decelerate to a stop, in time \$t_d = \frac {\left| v_0 \right|} a\$, at post-deceleration position \$p_d = p_0 + v_0 t_d - sign(v_0) \frac a 2 t_d^2\$. Now we're in the viable case and we can proceed as though we started at position \$p_d\$ with velocity 0, and add \$t_d\$ to the \$t_1\$ value we get below.


In the viable case, we can find the closest position we could reach with our current velocity before needing to slow down, \$p_L =\frac {v_0^2} {2a}\$, and accelerate until we're halfway there. This brings us exactly onto the approach curve where we can begin decelerating: after crossing the remaining half the distance to \$p_L\$, we'll again be moving with our original velocity since our acceleration and deceleration cancel each other out.

So our turnaround point when we begin decelerating is \$p(t_1) = \frac {p_0 + p_L} 2\$, and we can substitute this into the formula for \$p(t)\$ to solve for \$t_1\$ using quadratic formula.

Lastly, \$t_2 = \frac {v_0} a\$


This all relates to continuous physics. For discrete timesteps, we'll get some small errors (depending on your physics timestep and integration method), particularly from the frames where the acceleration may change midway through a timestep (flipping direction at the turnaround point, or ceasing upon reaching the target). You can adjust for this by applying a time-weighted average of the acceleration over the frame duration, or by clamping small errors upon arrival.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .