Sorry if this is posted before, but I didn't find an answer for this. I've been banging my head on this for a day now and I seems to be stuck.
I've implemented (see below) the 2D steering arrival behaviour described in http://www.red3d.com/cwr/steer/ which all works fine until there is a characters which wants to turn 180°. The character simply slows down, flips 180° and starts accelerating. I tried to illustrate this in Figure 1 (a).
Figure 1 - where red is the velocity and green the desired direction
What I would ideal like is a smoother path as seen in Figure 1 (b). I was thinking of using the clipped_speed
in combination with steering 'left' or 'right', however I can't seem to figure out how to do this with vectors. If anyone could point me in the right direction, that would be great.
The implementation (using libgdx)
Vector2 target_offset = target.sub(position);
float dist = target_offset.len();
float clipped_speed = Math.min(max_speed * (dist / (20 * mass)), max_speed);
desiredVelocity = target_offset.mul(clipped_speed / dist);
steeringForce = desiredVelocity.sub(this.velocity);
truncate(steeringForce, max_force);
Vector2 acceleration = steeringForce.mul(1 / mass * 60 * delta);
velocity.add(acceleration);
truncate(velocity, max_speed);
position.add(velocity.mul(60 * delta));
And the code for truncate:
public void truncate(Vector2 v, float max) {
float i = v.len() != 0 ? max / v.len() : 0;
if(i < 1) {
v.mul(i);
}
}
EDIT: Using bobobobo input I think I'm there. So for those interested:
Vector2 target_offset = target.position().sub(position);
float dist = target_offset.len();
float clipped_speed = Math.min(max_speed * (dist / break_dist * mass), max_speed);
desiredVelocity = target_offset.mul(clipped_speed / dist);
steeringForce = desiredVelocity.sub(velocity);
truncate(steeringForce, max_force);
forward = steeringForce.mul(1 / mass * 60 * delta);
float a = (float) (Math.acos(velocity.nor().dot(forward.nor())) * MathUtils.radDeg);
if(Float.isNaN(a)) a = 0;
if(a > max_rot) {
if(velocity.nor().crs(forward.cpy().nor()) < 0) {
forward.setAngle(velocity.angle() - max_rot);
} else {
forward.setAngle(velocity.angle() + max_rot);
}
}
velocity.add(forward);
truncate(velocity, dist < break_dist * mass ? dist / (break_dist * mass) * max_speed : max_speed);
Breaking is done by just scaling the velocity linearly, which isn't really all that nice implementation wise, but it give better stopping results. So we don't overshoot.