Talking about Racing game, Actionscript 3, Flash and Game development.
Finally it’s time to start talking about a real Artificial Intelligence algorithm. As said, I won’t use waypoints because I want to focus on “real” artificial intelligence, I want to make cars drive like if they were controlled by a player.
The idea
Let’s imagine you are driving a car, you aren’t blind so you can see the track.
If you see the track has a left turn, you turn left.
If you see the track has a right turn, you turn right.
You always accelerate, unless you see the turn is sharp
The code
This is how I made: the car has a line of sight like the one developed for the survival horror prototype.
This means is have i
lines of sight subdivided in j
segments.
Every line of sight can be done with all j
segments, if it never hits the track boundaries, or with a number n
from 0
and j-1
if it hits the track boundaries while drawing the n-th
segment.
When I have a line of sight made by j
or n
segments, I have to determine if this line is on the left or on the right side of the car. This can be easily done because if I have i
lines, all lines < i/2
will be on the left and the remaining ones will be on the right.
Now I have the number of segments before I hit track boundaries and I know if it’s on the left or on the right side of the car.
I increase a variable called turn_left
by the number of segments if the line is on the left side, or I decrease it if the line is on the right side.
In the ideal situation, when no lines hit track boundaries, turn_left
is zero
and the car continues straight.
If turn_left
is positive, I should turn left, if it’s negative I should turn right, but only if the absolute value is greater than a certain tolerance.
I don’t want my car to turn left and right just because a single line of sight hit the track boundaries.
Same thing for the acceleration: I do not accelerate only if the absolute value of turn_left
is greater than a certain tolerance.
Let’s translate it into AS3:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
public class car_mc extends Sprite {
public var acceleration:Number=0.4;
public var speed_decay:Number=0.96;
public var rotation_step:Number=15;
public var max_speed:Number=10;
public var back_speed:Number=1;
public var speed:Number=0;
// defining the angle of sight in degrees
public var angle_of_sight:Number=90;
// this is just a graphical representation of the line of sight
public var line_of_sight:Sprite = new Sprite();
// this is the accuracy: the higher, the better, the slower the simulation
public var sight_accuracy:int=15;
// this is the lenght of sight
public var sight_lenght:int=100;
// this is the number of steps required to complete the lenght of sight
public var sight_steps:int=20;
// this is the turning tolerance
public var turn_tolerance:int=10;
public function car_mc(posx:int,posy:int):void {
addChild(line_of_sight);
line_of_sight.graphics.lineStyle(1,0x000000);
line_of_sight.graphics.lineTo(100,100);
x=posx;
y=posy;
addEventListener(Event.ENTER_FRAME,on_enter_frame);
}
public function on_enter_frame(e:Event):void {
var angle_step:Number=angle_of_sight*2/sight_accuracy;
var sight_point:Point;
var global_sight_point:Point;
var par:racing=this.parent as racing;
// variable to hold line of sight collision results
var turn_left:int=0;
// variable to determine if the car is colliding with the ground
var colliding:Boolean=false;
line_of_sight.graphics.clear();
line_of_sight.graphics.lineStyle(1,0x000000);
for (var i:int=0; i<=sight_accuracy; i++) {
for (var j:int=1; j<=sight_steps; j++) {
line_of_sight.graphics.moveTo(0,-15);
sight_point= new Point(sight_lenght/sight_steps*j*Math.cos((-90-angle_of_sight+angle_step*i)*0.0174532925),sight_lenght/sight_steps*j*Math.sin((-90-angle_of_sight+angle_step*i)*0.0174532925));
global_sight_point=localToGlobal(sight_point);
if (par.ground.hitTestPoint(global_sight_point.x,global_sight_point.y,true)) {
// leaving the loop if the j-th segment of the i-th line of sight
break;
}
}
// if the line of sight is on the left, add the number of segments to turn_left variable
if (iturn_tolerance) {
if (turn_left>0) {
rotation -= rotation_step*(speed/max_speed);
} else {
rotation += rotation_step*(speed/max_speed);
}
}
}
if (Math.abs(speed)>0.3) {
speed*=speed_decay;
} else {
speed=0;
}
}
}
}
And this is the result:
As you can see, playing with rotation_step
, angle_of_sight
, sight_accuracy
, sight_lenght
, sight_steps
and turn_tolerance
you can have the car run by itself along the track.
The code is way to be perfect, and I know there are some cases it won’t work (but I won’t tell you when :))… anyway if you want to try it by yourself, just copy this new script into car_mc
class you can find at step 1.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.