Lightning Effect in AS3

Working on Flux, I was tasked with implementing the Electrolaser, which basically shoots a lightning arc at the target, and branches out to enemies around the target… fun stuff! I thought I would share with the interwebz the logic behind lightning generation (or the way I do it at least). But first, a demo of what it looks like!

This movie requires Flash Player 9

The example above features only 2 bolts so you can get a basic idea of the system. Click anywhere in the movie to start the generation. The bolts will strike the mouse!

The basic idea behind creating those lightning bolts is to start with a single line, or more accurately a segment. If you spent your geometry classes playing Snake on your graphing calculators (unlike me, of course), here’s a short reminder: a segment is a part of a line bounded by two points. It’s that simple. So first, you create the segment:

Create a segment

Then, the trick is to get the middle point of that segment and to offset it perpendicularly a short amount, like so:

Offset the middle point, creating 2 segments

And then, you guessed it: keep going until you get enough subdivisions to suit your needs.

Create ALL the segments!

Now on to the code side. First, i recommend creating a Segment class, which i outlined below:

public class Segment
{
	private var start_point:Point;
	private var end_point:Point;

	public function Segment(start:Point, end:Point)
	{
		start_point = start;
		end_point = end;
	}
	public function getStart():Point { return start_point; }
	public function getEnd():Point { return end_point; }
	public function getMiddle():Point
	{
		var middle:Point = new Point();
		middle.x = (start_point.x + end_point.x) / 2;
		middle.y = (start_point.y + end_point.y) / 2;
		return middle;
	}
}

Then , create a vector of Segments to store all your lightning bolts, and create the main bolt (in the example above, it goes from the top of the movie to the position of the mouse).

var bolts:Vector.<Segment> = new Vector.<Segment>();
bolts.push(new Segment(start_point, end_point));

Then, you create two segments out of the first one, while offsetting the middle a little:

bolts.push(new Segment(bolts[0].getStart(), bolts[0].getMiddle()));

// offset the end of the previous bolt
bolts[1].setEnd(offsetTangeant(getAngle(bolts[0].getStart(), bolts[0].getEnd()), bolts[1].getEnd(), (Math.random() - 0.5) * 10);

// create the second part of the bolt
bolts.push(new Segment(bolts[1].getEnd(), bolts[0].getEnd());

My offsetting function looks like this:

// offset a point orthogonally to the tangent
private function offsetTangeant(tan_angle:Number, point:Point, offset:Number):Point
{
	point.x += Math.cos(tan_angle + Math.PI / 2) * offset;
	point.y += Math.sin(tan_angle + Math.PI / 2) * offset;

	return point;
}
// get the angle between two points (radians)
private function getAngle(p1:Point, p2:Point):Number
{
	return Math.atan2(p2.y - p1.y, p2.x - p1.x);
}

And keep going until you have enough bolts! I find that 4-6 iterations is usually enough. After you have populated the “bolts” Vector, all you have to do is draw a line between all those segments, and voila.

Stay tuned for part 2, where we will see how to add branches to that main lightning bolt!