Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Actionscript 3, Box2D and Flash.

After I showed you various examples of destructible terrain created with Box2D (look here, here and here), it’s time to show you the full tutorial to create destructible terrain.

In this first part I won’t talk about Box2D, I am just showing you how to create a destructible terrain made of polygons.

The principle of the process is divide et impera. Since it would be complicated to manage a polygon with an hole in it, I am going to split a big polygon (the terrain) into a set of small polygons. How small? Small enough the hole made by an explosion can NEVER be completely inside them. This way I will never have real holes in my terrain.

Then it’s easy to use PolygonClipper class to manage polygon breaking.

Here is the script:

package {
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.events.MouseEvent;
	import com.logicom.geom.Clipper;
	import com.logicom.geom.ClipType;
	public class Main extends Sprite {
		// the canvas where we'll draw the terrain
		private var terrainCanvas:Sprite=new Sprite();
		// the array of polygons forming the terrain
		private var terrainPolygons:Array=new Array();
		public function Main():void {
			addChild(terrainCanvas);
			// creation of a 13x8 grid of squares, this will be our terrain
			for (var i:Number=0; i<13; i++) {
				for (var j:Number=0; j<8; j++) {
					var thePoly:Array = new Array(new Point(-5+i*50,80+j*50),new Point(45+i*50,80+j*50),new Point(45+i*50,130+j*50),new Point(-5+i*50,130+j*50));
					terrainPolygons.push(thePoly);
				}
			}
			// drawing the terrain
			drawTerrain();
			// listeners: basically we destroy the terrain with a mouse click or a mouse drag
			stage.addEventListener(MouseEvent.MOUSE_DOWN,function(){stage.addEventListener(MouseEvent.MOUSE_MOVE,doExplosion)});
			stage.addEventListener(MouseEvent.MOUSE_UP,function(){stage.removeEventListener(MouseEvent.MOUSE_MOVE,doExplosion)});
			stage.addEventListener(MouseEvent.CLICK,doExplosion);
		}
		// the core of the script, doExplosion function
		private function doExplosion(e:MouseEvent):void {
			// creation of an explosion polygon, looking like a circle, obviously it can be any shape you want
			var explosionPolygon:Array=createCircle(20,new Point(mouseX,mouseY),30);
			// for each existing terrain polygon, check the difference between the polygon itself and the 
			// explosion polygon. This should be optimized in some way, checking only for terrain polygons
			// which are actually affected by the explosion.
			// Then we remove the terrain polygon from the array, and we add the resulting polygon(s) after
			// difference is calculated.
			for (var i:Number=terrainPolygons.length-1; i>=0; i--) {
				var resultPolygons:Array=Clipper.clipPolygon(terrainPolygons[i],explosionPolygon,ClipType.DIFFERENCE);
				var totalArea:Number=0;
				terrainPolygons.splice(i,1);
				for (var j:Number=0; j<resultPolygons.length; j++) {
					terrainPolygons.push(resultPolygons[j]);
				}

			}
			// now it's time to redraw the terrain
			drawTerrain();
		}
		// function to create a "circular" polygon
		private function createCircle(precision:Number,origin:Point,radius:Number):Array {
			var angle:Number=2*Math.PI/precision;
			var circleArray:Array=new Array();
			for (var i:Number=0; i<precision; i++) {
				circleArray.push(new Point(origin.x+radius*Math.cos(angle*i),origin.y+radius*Math.sin(angle*i)));
			}
			return circleArray;
		}
		// these two remaining functions are not interesting, they just display the terrain
		private function drawTerrain() {
			terrainCanvas.graphics.clear();
			for (var i:Number=0; i<terrainPolygons.length; i++) {
				drawPolygon(terrainPolygons[i],terrainCanvas,0x0000FF);
			}
		}
		private function drawPolygon(polygon:Array,canvas:Sprite,color:Number):void {
			canvas.graphics.lineStyle(0.1,0xffffff);
			canvas.graphics.beginFill(color);
			var n:uint=polygon.length;
			if (n<3) {
				return;
			}
			var p:Point=polygon[0];
			canvas.graphics.moveTo(p.x, p.y);
			for (var i:Number = 1; i <= n; ++i) {
				p=polygon[i%n];
				canvas.graphics.lineTo(p.x, p.y);
			}
		}
	}
}

And this is the result:

Click to create a hole or drag to dig into the terrain.

Download the source code. Next time, we are going to add Box2D physics.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.