How to limit steering force at low velocities

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.

-
Just thinking out loud, it seems the main problem is the steering is simulating an object of zero size. Perhaps you can have steering at both engines and sum their forces to drive the ship? That would require them both to turn around the center of mass of the ship slowing down the rotation and possibly giving some more interesting flight characteristics. – Byte56 Feb 1 '13 at 23:02
I agree that this might be more interesting, but I like to keep movement simple. Mainly because AI needs to able to navigate too. Making the physics more complex, means complexer AI for movement which I do not want to spend too much time on. But I appreciate the though! – user1829378 Feb 2 '13 at 10:24

1 Answer

Just clip the maximum allowable rotation angle of the heading vector for the agent to something like 5 degrees/frame. (ie the red vector in your diagrams).

Right now your agents kind of have this omnidirectional capability to steer. You need to change that.

To get the agent to behave more like a car, an agent should only be able accelerate in the FORWARD direction. So you need to store an extra vector for the FORWARD vector of the agent.

The steering behaviors seek to modify the FORWARD vector. But if you clamp changes to the forward vector to a max of 5 deg /frame, turning will be smooth.

-
I see your point, however could you explain using vector math? I'm trying to implement this and having some difficulty. – user1829378 Feb 2 '13 at 13:53