Create a Flash racing game tutorial – Artificial intelligence

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 ilines, 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 (i<sight_accuracy/2) {
					turn_left+=j;
				} else {
					// if the line of sight is on the right, add the number of segments to turn_left variable
					turn_left-=j;
				}
				line_of_sight.graphics.lineTo(sight_point.x,sight_point.y);
			}
			// accelerate if turn_left is smaller than turn_tolerance*2
			if (speed<max_speed&&Math.abs(turn_left)<turn_tolerance*2) {
				speed+=acceleration;
			}
			var speed_x:Number=Math.sin(rotation*0.0174532925)*speed;
			var speed_y:Number=- Math.cos(rotation*0.0174532925)*speed;
			y+=speed_y;
			x+=speed_x;
			var point_left:Point=new Point(-9,0);
			var point_right:Point=new Point(9,0);
			var point_front:Point=new Point(0,-13);
			var point_back:Point=new Point(0,13);
			point_left=localToGlobal(point_left);
			point_right=localToGlobal(point_right);
			point_front=localToGlobal(point_front);
			point_back=localToGlobal(point_back);
			// car versus track boundaries collision management
			if (par.ground.hitTestPoint(point_left.x,point_left.y,true)&&par.ground.hitTestPoint(point_front.x,point_front.y,true)) {
				rotation+=5;
				speed*=0.85;
				colliding=true;
			}
			if (par.ground.hitTestPoint(point_right.x,point_right.y,true)&&par.ground.hitTestPoint(point_front.x,point_front.y,true)) {
				rotation-=5;
				speed*=0.85;
				colliding=true;
			}
			if (par.ground.hitTestPoint(point_front.x,point_front.y,true)) {
				speed*=0.55;
				colliding=true;
			}
			if (par.ground.hitTestPoint(point_back.x,point_back.y,true)) {
				speed*=0.55;
				colliding=true;
			}
			if (! colliding) {
				// turn left or right according to tolerance and turn_left value if the car is not colliding with track boundaries
				if (Math.abs(turn_left)>turn_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.

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (33 votes, average: 4.73 out of 5)
Loading ... Loading ...
Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.
Be my fan on Facebook and follow me on Twitter! Exclusive content for my Facebook fans and Twitter followers

This post has 31 comments

  1. Kaustav

    on June 28, 2010 at 12:13 pm

    That is quite awesome.

  2. Kaustav

    on June 28, 2010 at 12:14 pm

    If a little CPU expensive…=)

  3. szataniol

    on June 28, 2010 at 12:41 pm

    Majority of AI algorithms use some extra data, like waypoints or terrain map. The fact you are not using it doesn’t mean you do it better or more real. As a matter of fact your approach creates only limits.

    It is much more cpu consuming.
    You can’t determine wheter you’re going wrong way.
    You can’t tell how much distance you have left to the finish line or other cars.
    You can’t store any extra data like sensors, weapon pickup points, different types of terrain, shortcuts and so on.

    Artificial Intelligence NEED that kind of stuff. All you can do with this approach is car blindly going forward. If you would like to implement anything more complex and sophisticated you’ll get stuck.

    Cheers,
    szataniol

  4. Ozren

    on June 28, 2010 at 1:10 pm

    You rule !!

  5. Emanuele Feronato

    on June 28, 2010 at 1:28 pm

    terrain map is the next feature I am going to develop. With line of sight, I can avoid other cars too.

  6. pablopp

    on June 28, 2010 at 3:11 pm

    szataniol, why are you so concerned about this? As far as I understand, those experiments are not meant to end up as a real game, Emanuele is just trying out some interesting approaches, or am I missing the point here?

  7. Og2t

    on June 28, 2010 at 3:23 pm

    @pablopp Exactly!

    I like the experiment and idea, I’d use getObjectsUnderPoint instead of using hitTest and physical lines though. That way it could be used in conjunction with different tiles (terrain map approach).

    Keep it going Emanuele!

  8. elthing

    on June 28, 2010 at 5:28 pm

    Szataniol, it looks like you’re little bit jealous. Try to stick to your own job. Maybe use some glue ;)

  9. Monkios

    on June 28, 2010 at 5:45 pm

    In intelligence there is the possibility of error.

    This is awesome but it’s not AI.

  10. szataniol

    on June 28, 2010 at 9:22 pm

    I’m sorry if you percive my post like this. I just wanted to point that waypoints are inevitable if you are thinking about more complex AI. Sorry if anyone feel offended.

  11. Jacob

    on June 29, 2010 at 6:14 am

    I gotta say your a pretty smart cookie. That was a genius idea. So it’s not the AI we usually see. It def is a form of artificial intelligence.

  12. Kaustav

    on June 29, 2010 at 6:10 pm

    On the other hand, waypoints have their problems too.
    What if the terrain gets changed (new road/blockages)? If there are oil slicks or mines or any other fancy traps?
    Waypoints are predictable, which causes problems with playability. If weapons are added, AIs have to move out of their path to shoot the player, then what happens?

  13. Emanuele Feronato

    on June 29, 2010 at 6:23 pm

    Anyway Szataniol is right, you MUST use waypoints in some cases (just think about a track with a “8″ shape) unless you don’t want to flag (and permanently save) every mistake CPU car makes in order to have a more and more accurate driving model… too much for just a Flash game.

    I could try a waypoint approach in conjunction with line of sight.

  14. Thomas

    on June 29, 2010 at 11:38 pm

    I’d like to see this optimised to take the fastest line. Can it be done in any way so it always hits the apex of the curve? Then you’ve got the perfect AI – so, it’s a challenge for you, to prove you can beat waypoints! (Then you have to add imperfections, hooray.)

  15. Robert

    on June 30, 2010 at 4:53 am

    hey how is the road created..i cant find insid the sourvce..no movieclip or code that creates it

  16. Robert

    on June 30, 2010 at 5:59 am

    and how can i change the graphics in the movieclips??

  17. Robert

    on June 30, 2010 at 6:14 am

    nevermind…library was jsut messing up

  18. Cornelius

    on July 2, 2010 at 3:57 pm

    How are you calling your packages? I’ve tried to look at the source fla file, but I get an “Unexpected file error” when I attempt to open it.

  19. szataniol

    on July 5, 2010 at 4:19 pm

    @Kaustav – Waypoints doesn’t necessarily have to be x,y points. For example in a racing game the best approach I’ve seen is using convex sectors which consists of few x,y points, that allow you to precisely tell where is the car and what steps should it take next. You should check out this book:
    http://www.aiwisdom.com/bookshelf_aiwisdom.html
    I can honestly recommend it to anyone who’s interested in artificial intelligence for games.

    Cheers
    szataniol

  20. Straffehond

    on July 5, 2010 at 4:21 pm

    Love this. I wonder what the car does if the road splits ip. Will it go lefty, righty, or will it crash?

  21. Robert

    on July 9, 2010 at 5:48 am

    jsut tested it..you can do figure 8 tracs..it works great to…they dont get mixed up

  22. Weekly Digest for July 11th — Hello. My name is Václav Van?ura.

    on July 11, 2010 at 7:28 pm

    [...] Create a Flash racing game tutorial – Artificial intelligence – Emanuele Feronato [...]

  23. suresh

    on July 23, 2010 at 11:00 am

    hi admin,

    i like this script, i want to create racing car game for user view the track into the car , please give tutorials.

    thanks,
    suresh

  24. jose

    on July 24, 2010 at 11:36 pm

    too perfect the car’s trayectory no errors no little desviations look like it had a train track

  25. Neru Tu Kaze

    on August 16, 2010 at 1:12 pm

    Finally, Something that might will work as a heat tracing/targeting/homing missile!!! It was not what i where looking for right now. But this will work on my other project that i almost gave up, thanks!… I might be able to do some more stuff with this too :D …External code,AS 3.0 …Everything that i need ;D

    Thank you so much!, i have no idea how much time i’ve used trying to find a code that is in AS 3.0 and that works!

  26. Ivan

    on September 12, 2010 at 6:40 pm

    Looks intelligent alrighty! :D

  27. Dmillos

    on September 14, 2010 at 10:57 pm

    HI Emanuele, nice test, I really liked how it looks in the end, I made a very similar test a couple of months ago and it turned out pretty nice as well, in the end I had to add a couple of points so that the car would know which way to go in case he crashed or something, you can check it out here if you want:
    http://impudia.blogspot.com/search/label/Project%20Schumacher

    anyways, thanks for the blog, it is really cool

    -Daniel

  28. amarnath

    on May 26, 2011 at 6:17 pm

    fantastic

  29. amarnath

    on May 26, 2011 at 6:18 pm

    fantastic….simply superb

  30. Jay

    on September 18, 2011 at 1:51 pm

    How do I use this I dont know, When I download the step 1, then try to open the .fla file it wont open it says ‘unexpected file format’. Therefore how can i use the AI on my other racing game. Please help me I really need it.

  31. Cássio

    on December 15, 2011 at 7:30 pm

    The aproach used here is interesting, but you should try out something like neural networks, I developed one that could navigate well with only 3 “lines of sight” (I call them sensors)