I'm working on a 2D, top-down driving game with some basic AI vehicles. The AI Vehicles move along a bidirected graph of positions. Each vehicle has a current position (from the graph) and a target position, but instead of linearly interpolating directly between the positions, the vehicles each have a maximum steering angle, and so must steer their way to the next point.
The vehicle is defined geometrically as follows:
- The vehicle itself is a rectangle, comprising a center point (O), a width and a height.
- The vehicle has both a front (F) and rear (R) 'axis' from which the wheels are extruded.
- The vehicle is steered from the front axis, by an angle defined as (a). The vehicle's
- The current heading is (A).
- The current steering heading is (B).
- The desired target is (T).
The vehicle's heading is only changed when both the steering angle is set and there is some forward motion (i.e. the vehicle cannot turn when standing still).
As long as the target T is sufficiently far enough away, over time the vehicles can be correctly steered towards the targets.
The problem is, when the target is defined too close to the front axis, the vehicle can never reach the target, as the turning arc is too large (they drive around the target indefinitely).
I think the solution is to first detect if the target is 'too close', and if so, the vehicle needs to reverse a little first, and then begin driving forwards again. I think this would be achivable by defining a circle adjacent to the vehicle to detect if the target point can be reached based on the maximum turning angle and current position - but I don't know how to create such a circle. Something like:
How can I create a circle (the origin and radius) from the current vehicle position and max turn angle? Is there a different, potentially better solution?
Thanks a lot
edit The following is how I update the position of the vehicle. In a nutshell, the positions of the front and rear wheels are first calculated, and their positions are independently updated. Then the new position of the car is worked out from there. I cut a little for brevity, but it should be enough to see how it works:
private void updateVehicle(BaseVehicle pCar) {
final float lAccelerationAmt = 30;
final float lWheelBase = 32;
pCar.speed += lAccelerationAmt ;
// Extrude front and rear axels
pCar.frontWheels.x = pCar.x + lWheelBase / 2 * cos(pCar.rotation);
pCar.frontWheels.y = pCar.y + lWheelBase / 2 * sin(pCar.rotation);
pCar.rearWheels.x = pCar.x - lWheelBase / 2 * cos(pCar.rotation);
pCar.rearWheels.y = pCar.y - lWheelBase / 2 * sin(pCar.rotation);
// Move the vehicle
pCar.rearWheels.x += pCar.speed * delta * cos(pCar.rotation);
pCar.rearWheels.y += pCar.speed * delta * sin(pCar.rotation);
pCar.frontWheels.x += pCar.speed * delta * cos(pCar.rotation + pCar.steerAngle);
pCar.frontWheels.y += pCar.speed * delta * sin(pCar.rotation + pCar.steerAngle);
// Extrapolate the new car location
pCar.x = (pCar.frontWheels.x + pCar.rearWheels.x) / 2;
pCar.y = (pCar.frontWheels.y + pCar.rearWheels.y) / 2;
// update the vehicle heading
pCar.rotation = atan2(pCar.frontWheels.y - pCar.rearWheels.y, pCar.frontWheels.x - pCar.rearWheels.x);
}