I have a point entity that I would like to move to a target point (in 2D).

I think I would like it to accelerate away from its current position (the point could already have a velocity), to some maximum velocity, and decelerate as it approaches the target, eventually coming to a stop on the target.

I think both the acceleration and deceleration should have constant magnitudes, but given that the entity can have a velocity, which may not be in the same direction as the target, the direction of the acceleration/deceleration could be different every frame.

I am not coding in any particular language or framework yet, and just want to know if this is easy/possible. Am I describing something that is quite common (like a targeted missile that stops at the target/an AI controlled space ship in a game)? If it is hard, is there another way I can achieve the same kind of motion?

  • \$\begingroup\$ Is the target still? \$\endgroup\$ – FxIII Apr 19 '14 at 10:21
  • \$\begingroup\$ @fxlll Yes, the target is stationary. It's position could be changed by the user (hence the moving entity could have an unrelated starting velocity from a previous target), but it will not change of its own accord. \$\endgroup\$ – user44770 Apr 19 '14 at 11:44
  • \$\begingroup\$ how the acceleration vector is costrained? \$\endgroup\$ – FxIII Apr 19 '14 at 17:22
  • \$\begingroup\$ @FxIII I am not sure. I just imagine there would be an acceleration away from the start point, till maximum speed is reached, and then a deceleration as it approaches the target. The point could already be moving towards the target, so acceleration may not be needed. Acceleration and deceleration could have the same magnitude in opposite directions, but need to stop any velocity in a perpendicular direction from entity to target, to stop the thing going into orbit. \$\endgroup\$ – user44770 Apr 19 '14 at 23:41

You need to know when to begin slowing down.

To compute this, you need to know your current speed and the distance from the target.

Let V be your current speed and d be the current distance. We'll also need a which is your acceleration and deceleration rates and t which is the time it takes to stop at the current speed.

You'll begin slowing down when the following condition is met:

t = V / a;
if ( V * t / 2.0 >= d ) //begin to slow down

You can find more about deceleration here.

Otherwise you'll want to speed up towards the target. Lets define cx, cy as the position of the chasing entity and tx, ty as the position of the target. dvx and dvy will be the desired velocity for the one chasing and vx, vy will be the current velocity.

deltaX = tx - cx;
deltaY = ty - cy;
distance = sqrt(deltaX^2 + deltaY^2);
dvx = deltaX * maxSpeed / distance; //Normalizing and multiplying by max speed
dvy = deltaY * maxSpeed / distance;
deltaX = dvx - vx;
deltaY = dvy - vy;
diffSize = sqrt(deltaX^2 + deltaY^2);
ax = maxAcc * deltaX / diffSize;
ay = maxAcc * deltaY / diffSize;

vx += ax * dt // dt is the time that passed since the last frame
vy += ay * dt // 

As zehelvion stated, you need to know when to begin slowing down. However, simply reaching the halfway point time-wise is not precise, especially if the acceleration is different from the deceleration. In fact working out the time just so we can calculate that is more tedious than using the distance.

The distance that you need to decelerate fully can be given by the following physics formula:

2ad = Vf^2 - Vi^2

a is the acceleration (or in this case, the deceleration or traction), d is the distance we need to work out, Vf is the final speed (in this case, it's 0), Vi is the speed before accelerating, in this case it's our normal velocity. After working out the formula (and considering that the deceleration is negative, but for the sake of simplicity, we will use a positive value in the code) gives us the following:

d = Vi^2 / 2a, which makes the code as following:

deaccDistance = velocity^2 / (2 * DECELERATION);

Lets define 'x', 'y' as the position of the chasing entity and 'targetX', 'targetY' as the position of the target. dt is the time that passed since the last frame. ACCELERATION, DECELERATION, TOPSPEED are constants

deltaX = targetX - x;
deltaY = targetY - y;
distance = Math.Sqrt(deltaX^2 + deltaY^2);
decelDistance = velocity ^ 2 / (2 * DECELERATION);

if (distance > decelDistance) //we are still far, continue accelerating (if possible)
    velocity = Math.Min(velocity + ACCELERATION * dt, TOPSPEED);
else    //we are about to reach the target, let's start decelerating.
    velocity = Math.Max(velocity - DECELERATION * dt, 0);

cx += velocity * cosangle * dt;
cy += velocity * sinangle * dt;

If the target is stationary, you can calculate the cosangle and sinangle beforehand, otherwise you will need to calculate them on every frame.. for reference:

angle = Math.Atan2(deltaY,deltaX);
cosangle = Math.Cos(angle);
sinangle = Math.Sin(angle);

This would work, if the dt is a constant, however it will vary from a frame to another, so we have to add a check before the code:

if distance < (velocity * dt) then      --we almost reached it, skip the rest
    x = targetX;
    y = targetY;
    velocity = 0;

And that's pretty much it, you can add a variable named finished and call it as appropriate to be absolutely sure that it doesn't break, or make more checks to see if the lastdistance was bigger than the current distance and in that case you can snap the object to the target, but usually, this is not required.

  • \$\begingroup\$ Lots of great little tips in this answer. I knew it must be possible to do it based on distance rather than time so thank you very much. This should be the accepted answer. \$\endgroup\$ – Joe Jankowiak Jul 18 '20 at 23:02
  • \$\begingroup\$ Should be the accepted answer. Thank you. Really helpful post. \$\endgroup\$ – picolino Sep 13 '20 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.