0
\$\begingroup\$

I hope the question title makes sense. I haven't been able to google for an answer because I don't know what the correct terminology I'm looking for is.

Basically, I have an actor / enemy / game object:

actor
{
    vector2f position;
    vector2f velocity;
    float maxSpeed;
    float acceleration;
}

And every time slice / game loop, I'm checking what direction the enemy should head in. With this direction, I then update the actor's position based on their velocity with acceleration adjustments:

update_actor_position(const float elapsedTime)
{
    vector2f newDirection = figure_out_actor_direction_to_go(); // gives a normalised vector direction
    float additionalSpeed = acceleration * elapsedTime; // all my values are in milliseconds
    velocity += newDirection * additionalSpeed;
    
    /* capping velocity at max speed, removed for brevity */

    position += velocity * elapsedTime;
}

But the problem is the old direction they were heading in isn't changed by the newDirection. So they move like the ship from Asteroids.

But I don't want to just stop all velocity and start again with each new frame, or each change in direction. Sometimes the direction change is only small, in which case they should gradually adapt to this new direction.

In addition, I'm sure my max speed capping is incorrect because I'm not capping the total speed of box x and y at the same time, but instead capping x and y separately to a single value. Any help there would also be appreciated, but I'm more confident in being able to figure that one out myself.

\$\endgroup\$
2
  • \$\begingroup\$ Here's a method that's worked well for me, using the notion of accelerating toward a target velocity, subject to some limiting acceleration that's greater when dramatically changing direction. \$\endgroup\$
    – DMGregory
    Commented May 15 at 11:14
  • \$\begingroup\$ @DMGregory that's exactly what I was looking for! Thank you. \$\endgroup\$ Commented May 16 at 10:17

2 Answers 2

0
\$\begingroup\$

You could try making the acceleration proportional to the difference in angle. The latter could be computed using functions like this:

// Calculates the shortest difference between two given angles.
function deltaAngle(current: number, target: number) {
  let delta = repeat(target - current, Math.PI * 2);
  if (delta > Math.PI) delta -= Math.PI * 2;
  return delta;
}

function clamp(value: number, min: number, max: number) {
  return Math.max(min, Math.min(max, value));
}

// Loops the value t, so that it is never larger than length and never smaller than 0.
function repeat(t: number, length: number) {
  return clamp(t - Math.floor(t / length) * length, 0, length);
}

Source.

\$\endgroup\$
0
\$\begingroup\$

I'm not sure entirely what you are after, but I think this might do what you want: https://github.com/paulsinnett/DirectionChange

The guts of the calculation of the acceleration vector is:

        Vector3 vChange = -velocity + direction * maxSpeed;
        Vector3 vAcceleration = vChange.normalized * acceleration;
        Vector3 newVelocity = ClampVector(velocity + vAcceleration * deltaTime, maxSpeed);
        position += 0.5f * (velocity + newVelocity) * deltaTime;
        velocity = newVelocity;

Oh, and the clamp function for a vector is:

    static Vector3 ClampVector(Vector3 v, float max)
    {
        if (v.sqrMagnitude > max * max)
        {
            v = v.normalized * max;
        }
        return v;
    }
\$\endgroup\$

You must log in to answer this question.

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