race cars turning between path around track

BlitzMax Forums/MiniB3D Module/race cars turning between path around track

redmoth(Posted 2013) [#1]
I'm experimenting with race cars following a preset path of coordinates (checkpoints) around a race track. The current system works, but currently the cars immediately rotate to the next checkpoint and I'm trying to get them to turn smoothly, and hopefully from this I can work out how fast they should go to be able to turn.

My car has a max speed of 3, and a max turning of 3, (MAX_TURN), which is the maximum it can turn every loop.

I also reduce the max the car can turn at higher speeds for example:
		If inputSteer < 0 Then
			mesh.TurnEntity(0,((inputSteer*MAX_TURN)+(speed/2)),0)
		Else If inputSteer > 0
			mesh.TurnEntity(0,((inputSteer*MAX_TURN)-(speed/2)),0)
		End


So, for the computer cars I want to work out how far they have to turn to the next checkpoint and if it's greater than MAX_TURN, slow the car down.


Currently, I'm just pointing the computer cars to the next checkpoint
If EntityDistance(mesh,targetPivot) <= 9 Then 'if near to the checkpoint
    checkPoint+= 1
    mesh.RotateEntity(DeltaPitch(mesh,targetPivot)*0.9,DeltaYaw(mesh,targetPivot)*0.9,0.0)
    targetPivot.PositionEntity(nxtCheckX,-2,nxtCheckZ) 'move the cars target pivot to the next checkpoint X and Z locations	
End


My best idea is something like this, but I'm not a great mathematician and am not sure if my idea is flawed:
1. get the DeltaYaw between the car and the checkpoint
DeltaYaw(mesh,targetPivot)
2. Divide it by the distance between the car and the targetPivot
3. Divide that by the maximum turn speed at that speed ie: leftToTurn:float = (TURN_SPEED)+(speed/2)
4. If the remaining angle s greater than the leftToTurn variable then slow the car down slightly.

Any help would be appreciated.
(In the code above I'm using minib3d + monkey, but also have minib3d and blitzmax if that's easier)

Images, if it's easier:





Chapman7(Posted 2013) [#2]
I would use a Bezier Curve

(Wayback machine to the wordpost that helped me)
http://web.archive.org/web/20100204203840/http://gurumeditations.wordpress.com/articles/calculating-and-drawing-bezier-curves-with-blitzmax/

You can make how ever many points you want for a more smoother turn

EDIT: Just realized this is for 3d though. I am sure you can work something for it out.


redmoth(Posted 2013) [#3]
Thanks, I understand more or less what a bezier curve is, but I'm having trouble thinking how to adapt it to my ai cars.

each checkpoint has an x, and z location and also a rotation.

would P0 be the current checkpoint and P2 be the next checkpoint,
a bit confused over p1,
would it be p2-p1 * speed?

Sorry, maybe it's late for me and my head is playing stupid.


Kryzon(Posted 2013) [#4]
I agree that you need a spline for that.
The way it is being done now, every car has to pass exactly through each waypoint, and that's unrealistic especially in tighter curves. Two cars side by side would come into contact trying to go through the same waypoint.

You can use Catmull-Rom splines for this.
The good thing about them is that they pass through their control points (so are easy to define), are fast to compute and can be cyclic, so you can define a closed circuit with them - for this you'd need several different splines connected to each other.

A few resources:
- Interview with a F-Zero X hacker and how the tracks for that game are laid out. Has some information and images that may spark ideas: http://www.pressthebuttons.com/2005/08/some_words_with.html

- Direct3D demo of Catmull-Rom for a vehicle in a highway: http://www.mvps.org/directx/articles/catmull/

- More on Catmull-Rom: http://www.booncotter.com/waypoints-catmull-rom-splines/

- Steering behaviors theory (look for the Path Following article): http://www.red3d.com/cwr/steer/

- Blitz code archives:
http://blitzbasic.com/codearcs/codearcs.php?code=1522
http://blitzbasic.com/codearcs/codearcs.php?code=1761
http://blitzbasic.com/codearcs/codearcs.php?code=3011

You'll need to find the tangents of the spline at specific points on the curve so you know where the vehicles should point at any time.

A tangent is the straight line this dot is carrying:



You can calculate that tangent fast if you have the previous and future locations of the car on the spline. The tangent for (currentPoint) is the vector from (oldPoint) to (futurePoint).
Remember that this is calculated as a delta (future - past), so the result is:

currentPoint.tangentX = futurePoint.positionX - oldPoint.positionX
currentPoint.tangentZ = futurePoint.positionZ - oldPoint.positionZ

Instead of Y it's Z because, as you've said it, viewing from above has you working on the XZ plane.
With this tangent you can use AlignToVector, and so each car is aligning to be parallel with the spline instead of trying to pass through the points that define it. You can have several cars distributed over a spot and they'll all remain to their "local" directions.
My suggestion is that at the beginning of the race you calculate not only the current point on the spline for each car, but also the future point. This way every frame you're calculating the future point only, and the next frame passing it along for the car as "current point", and the car's previous current point is now the old point with which you can calculate the current tangent direction.
Note the cars are never placed on these points on the spline - these points only serve to calculate tangents. The cars can mantain their distance from the spline so they can occupy the track however you want, with formations or lineups etc.

Another method you'll need is finding the point on the spline that's closer to the car (this is used when you want to start the race and need to find out the closest point on the spline for a given car), but I believe this can be approximated by treating the spline as a polyline: each pair of points defines a line segment, and you just need to get the closest distance of a point to a line segment for this, and normalize this closest point (i.e, divide the length of the section of the segment from the starting point to the closest point discovered, by the length of the entire segment which is from the starting point to the end point) to obtain the spline's 't' argument.