Path Finding - part 1

Path finding, it’s used a lot in games, such as Age of Empires, and involves something getting from point A to point B. Though it’s not as simple as that. It’s got to go around objects, finding the quickest route etc. Well lets start with something small and build our path finding engine up.

I’m using Actionscript (AS) 2, and I’d recommend having you’re frames per second (FPS) at around 30. Sorted? Perfect.

Now firstly lets make our two points, point A and point B. These will be just two circles which we can drag and drop around. So draw two circles, turn them into movie clips and give one the instance name of “pointA” and the other of “pointB”. Now on the frame (it’s a good habit to code on the frame!) put this code:

pointA.onPress = function() {
	//when you click on the MC pointA
	this.startDrag();
	//start dragging :O
};
pointB.onPress = function() {
	//same thing for pointB
	this.startDrag();
};
function onMouseUp() {
	//when the mouse is up
	pointA.stopDrag();
	pointB.stopDrag();
	//stop the dragging of both MCs
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Now so long as you gave the two Movie Clips the correct instance names it should be working. Notice how instead of stopping the drag using an onRelease method we have onMouseUp? Well that’s so if you’re moving your mouse too fast when you release the dragging won’t continue. Now create our first path!

We’re going to use some API here, if you don’t know much about it I’d suggest researching it before continuing. Now we want to draw a line between pointA and pointB. Lets make an empty movie clip which will be used for the line, and a function of it drawing.

this.createEmptyMovieClip("path", 1);
//create a movie clip with the instance name of "path"
function drawLines() {
	path.lineStyle(5, 0xFF0000, 100);
	//give it a line style. You can change the colour if you want to
	path.moveTo(pointA._x, pointA._y);
	//move to pointA's position
	path.lineTo(pointB._x, pointB._y);
	// move to pointB's position
}
drawLines();
pointA.onPress = function() {
	//when you click on the MC pointA
	this.startDrag();
	//start dragging :O
};
pointB.onPress = function() {
	//same thing for pointB
	this.startDrag();
};
function onMouseUp() {
	//when the mouse is up
	pointA.stopDrag();
	pointB.stopDrag();
	//stop the dragging of both MCs
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

So we’ve made a new movie clip named “path” and we’ve given it a line style. In our function we moved “path” to “pointA”’s position and we’ve drawn a line to “pointY”’s position. Now if you test that you find the lines are connecting to your circle’s top left hand corner. That’s because we need to center our circles on the little +. Go inside your circle and move it so that the + is in the middle. Great, now it works fine!

However when we drag our circles the line stays still. Well that’s why we put it in a function, so we can update the line’s position at any time. However we don’t want to update it all the time, only when the circles move. Now if you think about it we can just add that function whenever we release our circles, or when the mouse is up (!). The only problem now is that we’ll be drawing a new line, but the old one will still be there! We’ll have to clear it when we click on our circles. So our code should now be:

this.createEmptyMovieClip("path", 1);
//create a movie clip with the instance name of "path"
function drawLines() {
	path.lineStyle(5, 0xFF0000, 100);
	//give it a line style. You can change the colour if you want to
	path.moveTo(pointA._x, pointA._y);
	//move to pointA's position
	path.lineTo(pointB._x, pointB._y);
	// move to pointB's position
}
drawLines();
pointA.onPress = function() {
	//when you click on the MC pointA
	this.startDrag();
	//start dragging :O
	path.clear();
	//clear our current line
};
pointB.onPress = function() {
	//same thing for pointB
	this.startDrag();
	path.clear();
	//clear our current line
};
function onMouseUp() {
	//when the mouse is up
	pointA.stopDrag();
	pointB.stopDrag();
	//stop the dragging of both MCs
	drawLines();
	//our line function
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Perfect! We’ve just created our first ever path! Now for the hard part - obstacles in the way. Lets a square and give the instance name of “square”. Now we want to see when the line hits the square and then we can draw it. So what we do is

Check if where line would be is colliding with object —> Draw line to object

Simple enough. Though what we’re going to do next isn’t. This is going to drop us right in the deep end, starting with some math. This will be our new function to replace the old one:

function drawLines() {
	path.lineStyle(5, 0xFF0000, 100);
	//give it a line style. You can change the colour if you want to
	var pathAngle:Number = Math.atan2(pointB._y-pointA._y, pointB._x-pointA._x);
	//get the angle of the line
	for (var i:Number = 1; true; i++) {
		//run a for loop for the hit test forever...
		var toX:Number = pointA._x+i*Math.cos(pathAngle);
		//making a variable gets the x pixel of the line
		var toY:Number = pointA._y+i*Math.sin(pathAngle);
		//making a variable gets the y pixel of the line
		if (square.hitTest(toX, toY, true) || pointB.hitTest(toX, toY, true)) {
			//if the path hits either the square or the point at the set pixel
			break;
			//stop the infinite loop!
		}
	}
	path.moveTo(pointA._x, pointA._y);
	//start the line back to where it started
	path.lineTo(toX, toY);
	//move to where the collision happened
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Now let me elaborate. We don’t need to draw our original line, because it won’t help us in any way. Then we get the line’s rotation using the coordinates of “pointA” and “pointB”. We then run an INFINTE loop - that’s why the condition is put as true. Don’t worry, this won’t crash Flash because it will be broken eventually. So now we have some math. We get the starting point of the line, then we get the pixel where the line will be because we know its angle. Because of the for loop we get EVERY pixel the line is going on, because unfortunately we can only hit test one pixel at a time. This may sound a little confusing, so I included a diagram to help explain it.

Now we check our new coordinates of where the line could be hit against the square and “pointB”. We check whether when it will hit pointB so that we know when to stop the for loop. Now we draw the line to the coordinates where the path collided with something. Tadaa! Now our whole code should be:

this.createEmptyMovieClip("path", 1);
//create a movie clip with the instance name of "path"
function drawLines() {
	path.lineStyle(5, 0xFF0000, 100);
	//give it a line style. You can change the colour if you want to
	var pathAngle:Number = Math.atan2(pointB._y-pointA._y, pointB._x-pointA._x);
	//get the angle of the line
	for (var i:Number = 1; true; i++) {
		//run a for loop for the hit test forever...
		var toX:Number = pointA._x+i*Math.cos(pathAngle);
		//making a variable gets the x pixel of the line
		var toY:Number = pointA._y+i*Math.sin(pathAngle);
		//making a variable gets the y pixel of the line
		if (square.hitTest(toX, toY, true) || pointB.hitTest(toX, toY, true)) {
			//if the path hits either the square or the point at the set pixel
			break;
			//stop the infinite loop!
		}
	}
	path.moveTo(pointA._x, pointA._y);
	//start the line back to where it started
	path.lineTo(toX, toY);
	//move to where the collision happened
}
drawLines();
pointA.onPress = function() {
	//when you click on the MC pointA
	this.startDrag();
	//start dragging :O
	path.clear();
	//clear our current line
};
pointB.onPress = function() {
	//same thing for pointB
	this.startDrag();
	path.clear();
	//clear our current line
};
function onMouseUp() {
	//when the mouse is up
	pointA.stopDrag();
	pointB.stopDrag();
	//stop the dragging of both MCs
	drawLines();
	//our line function
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

In the next part we’ll draw around the square when it collides with it, and get to where we want to go. If you have any questions, comments or suggestions then feel free to post.

Source Codes

Part 2

2 Responses to “Path Finding - part 1”

  1. Adarsh Sinha says:

    Very good tutorial.
    Finally a simple and easy to understand pathfinding tutorial!
    Can’t wait for part 2, although i did have an idea on how to come across the obstacle.
    To explain :
    Suppose the ray hits the left side of the obstacle(in this case,square), we then calculate the distance between the edges of that side through distance formulas(those are very simple) then through some conditional if/elses, we move/lineto the closest edge, move the pen a little more up/down and the go across to the obstacle.

    Its not full-proof nor complete, just an idea .
    :)
    ~Adarsh Sinha

  2. Derrickxyz says:

    i love this…….

    u my inspiration…

    keep up the good work……..

Leave a Reply