AS3 2D Ray Casting For Collision Detection
Ray casting is a technique usually used in 3D worlds (often for rendering). Ray casting is exactly what it implies a ray is cast from a start point until it hits something (or a max length, so the computer doesn’t die). Ray casting in 2D is great for collision detections, especially fast-moving objects (bullets).
In this post, we will learn the basics of ray casting in 2D, then we will apply it to bullets in a simple environment.
A ray is just a line. It has a start point and an end point. In order to use this method effectively, we need to cast our rays fast. To do this, we will use Bresenham’s line algorithm. It is the fastest way to draw a line. It doesn’t support anti-aliasing, but that isn’t important to us because we won’t ever see the line (if we wanted to see the line, we would just ask flash’s graphics engine to draw a line for us).
We will be using the Vector2D.as class for this as well.
public static function bresenhamLine(start:Vector2D,end:Vector2D):Array {
var points:Array = [];//the array of all the points on the line
var steep:Boolean = Math.abs(end.y-start.y) > Math.abs(end.x-start.x);
This is a bit tricky. The algorithm only draws lines with a slope of less than 1. In order to draw steeper lines, we reflect the line across y=x to get a smaller slope.
var swapped:Boolean = false;
if(steep){
start = swap(start.x,start.y);//reflecting the line
end = swap(end.x,end.y);
}
if(start.x > end.x){ //make sure the line goes downward
var t:Number = start.x;
start.x = end.x;
end.x = t;
t = start.y;
start.y = end.y;
end.y = t;
swapped = true;
}
var deltax:Number = end.x-start.x;//x slope
var deltay:Number = Math.abs(end.y-start.y); //y slope, positive because the lines always go down
var error:Number = deltax/2; //error is used instead of tracking the y values.
var ystep:Number;
var y:Number = start.y;
if(start.y < end.y) ystep = 1;
else ystep = -1;
for(var x:int = start.x; x < end.x; x++){//for each point
if(steep){
points.push(new Vector2D(y,x));//if its steep, push flipped version
} else {
points.push(new Vector2D(x,y));//push normal
}
error -= deltay;//change the error
if (error < 0){
y += ystep;//if the error is too much, adjust the ystep
error += deltax;
}
}
if(swapped) points.reverse();
return points;
}
private static function swap(x:Number,y:Number):Vector2D {
return new Vector2D(y,x)
}
For more information about Bresenham’s Algorithm, you can read this article.
Now that we can cast rays, we need to determine if they are intersecting with any shape. This is ray casting’s main advantage over the separation of axis theorem. Unlike SAT, ray casting works with convex and concave polygons as well as circles.
Dealing with circles is easy:
for (i = 0; i < ray.length; i++) {//where ray is the array of points returned from the bresenhamLine function
var d:Number = Math2.distance(ray[i].x,ray[i].y,circle.x,circle.y);//get the distance between the point and circle
if(d < circle.radius) return true;//if distance is less than radius, they are touching
}
return false;//if you tested all the points and none were touching, there is no collision
Polygons are a bit more complicated. For this we will test each point against the polygon using the point-in-polygon algorithm.

The point in polygon algorithm detects the edges of the polygon, then it tests how many edges are on both sides of the point. If there are an even number of blue points, then the point is outside the polygon. If there are an odd number of blue points, the point is in the polygon.
In as3:
public static function pointInPoly(point:Vector2D,poly:RayShape):Boolean {
point is a point from the ray. You must loop through each point in the ray until you find one that collides.
var sides:int = poly.vertices.length;//amount of sides the polygon has
var i:int = 0;
var j:int = sides-1;
var oddNodes:Boolean = false;//how many sides have we passed through?
for(i = 0; i < sides; i++){//for each side
if((poly.vertices[i].y < point.y && poly.vertices[j].y >= point.y) || (poly.vertices[j].y < point.y && poly.vertices[i].y >= point.y)){//detect edges
if(poly.vertices[i].x+(point.y-poly.vertices[i].y)/(poly.vertices[j].y-poly.vertices[i].y)*(poly.vertices[j].x-poly.vertices[i].x) < point.x){//detect edges
oddNodes = !oddNodes;//if that was an edge, switch oddNodes
}
}
j = i;
}
return oddNodes;//return oddNodes
}
Odd nodes is either true or false. True if you are inside the poly, false if you are outside the poly.
A rayshape looks like this:
package com.rocketmandevelopment.collisions.raycasting {
import com.rocketmandevelopment.math.Vector2D;
import flash.display.Graphics;
public class RayShape {
public var vertices:Array;
public function RayShape(vertices:Array){
this.vertices = vertices;
}
public function move(velocity:Vector2D):void {
var len:int = vertices.length
for (var i:int = 0; i < len; i++) {
vertices[i].add(velocity);
}
}
public function setPosition(position:Vector2D):void {
var diff:Vector2D = position.subtract(middle());
var len:int = vertices.length
for (var i:int = 0; i < len; i++) {
vertices[i].add(diff);
}
}
public function middle():Vector2D {
var mid:Vector2D = new Vector2D();
var len:int = vertices.length
for (var i:int = 0; i < len; i++) {
mid.add(vertices[i]);
}
mid.divide(vertices.length);
return mid;
}
public function debugDraw(graphics:Graphics):void {
graphics.lineStyle(0);
graphics.moveTo(vertices[0].x,vertices[0].y);
var len:int = vertices.length
for (var i:int = 0; i < len; i++) {
graphics.lineTo(vertices[i].x,vertices[i].y);
}
}
}
}
All a rayshape does is hold the location of each vertex and move it around.
| Print article | This entry was posted by rocketman on July 8, 2010 at 11:01 AM, and is filed under AS3, Algorithms, Collision Detection. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |








about 1 year ago
Hi , I read your algorithm of ray detect, but I still can’t understand how much lines do we need to draw when we use this algorithm?
about 1 year ago
You only need to draw/cast as much of a line as you want.
Let’s say you’re using ray casting to simulate a gun shot. The length(amount you draw) of the ray would be the max distance the bullet can travel.
The best way to determine how much to draw is to use it, and play around with the distance until you find a good amount.
about 1 year ago
Since it up to programmer to decide how much to draw/cast , how can it make sure 100% percent all objects will be checked?
(The old method to traversal all objects in the stage can make sure every collided object be checked)
about 1 year ago
Great tutorial, I read the article and wiki and now have my very first raycasting system up and running in about 20 minutes. It’s so cool!