Talking about Actionscript 3, Box2D and Flash.
Look at the title… Create REAL explosions with Box2D… keyword: REAL.
This means we will make a Box2D explode into pieces using the basics of Slicing, splitting and cutting objects with Box2D. At the moment it’s just a prototype but it does not need that much optimization.
That’s what we’ll get:
Click the mouse to make the box explode.
Too fast? Get this slow motion example:
As you can see, this is a real explosion.
This is the source code, can you discover how was it possible?
package {
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
public class Main extends Sprite {
private var world:b2World=new b2World(new b2Vec2(0,10),true);
private var worldScale:int=30;
private var laserSegment:b2Segment;
private var drawing:Boolean=false;
private var affectedByLaser:Vector.;
private var entryPoint:Vector.;
public function Main() {
debugDraw();
addWall(320,480,640,20);
addWall(320,0,640,20);
addWall(0,240,20,480);
addWall(640,240,20,480);
addWall(320,240,200,200);
addEventListener(Event.ENTER_FRAME, updateWorld);
stage.addEventListener(MouseEvent.MOUSE_DOWN,mousePressed);
}
private function mousePressed(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_DOWN,mousePressed);
var cutAngle:Number;
for (var i:Number=0; i<5; i++) {
cutAngle=Math.random()*Math.PI*2;
laserSegment=new b2Segment();
laserSegment.p1=new b2Vec2((320+i/10-200*Math.cos(cutAngle))/worldScale,(240-200*Math.sin(cutAngle))/worldScale);
laserSegment.p2=new b2Vec2((320+200*Math.cos(cutAngle))/worldScale,(240+200*Math.sin(cutAngle))/worldScale);
affectedByLaser=new Vector.();
entryPoint=new Vector.();
world.RayCast(laserFired,laserSegment.p1,laserSegment.p2);
world.RayCast(laserFired,laserSegment.p2,laserSegment.p1);
}
}
private function debugDraw():void {
var debugDraw:b2DebugDraw = new b2DebugDraw();
var debugSprite:Sprite = new Sprite();
addChild(debugSprite);
debugDraw.SetSprite(debugSprite);
debugDraw.SetDrawScale(worldScale);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
debugDraw.SetFillAlpha(0.5);
world.SetDebugDraw(debugDraw);
}
private function addWall(pX:Number,pY:Number,w:Number,h:Number):void {
var wallShape:b2PolygonShape = new b2PolygonShape();
wallShape.SetAsBox(w/worldScale/2,h/worldScale/2);
var wallFixture:b2FixtureDef = new b2FixtureDef();
wallFixture.density=0;
wallFixture.friction=1;
wallFixture.restitution=0.5;
wallFixture.shape=wallShape;
var wallBodyDef:b2BodyDef = new b2BodyDef();
wallBodyDef.position.Set(pX/worldScale,pY/worldScale);
var wall:b2Body=world.CreateBody(wallBodyDef);
wall.CreateFixture(wallFixture);
}
private function updateWorld(e:Event):void {
world.Step(1/30,10,10);
world.ClearForces();
world.DrawDebugData();
}
private function laserFired(fixture:b2Fixture,point:b2Vec2,normal:b2Vec2,fraction:Number):Number {
var affectedBody:b2Body=fixture.GetBody();
var affectedPolygon:b2PolygonShape=fixture.GetShape() as b2PolygonShape;
var fixtureIndex:int=affectedByLaser.indexOf(affectedBody);
if (fixtureIndex==-1) {
affectedByLaser.push(affectedBody);
entryPoint.push(point);
}
else {
var rayCenter:b2Vec2=new b2Vec2((point.x+entryPoint[fixtureIndex].x)/2,(point.y+entryPoint[fixtureIndex].y)/2);
var rayAngle:Number=Math.atan2(entryPoint[fixtureIndex].y-point.y,entryPoint[fixtureIndex].x-point.x);
var polyVertices:Vector.=affectedPolygon.GetVertices();
var newPolyVertices1:Vector.=new Vector.();
var newPolyVertices2:Vector.=new Vector.();
var currentPoly:int=0;
var cutPlaced1:Boolean=false;
var cutPlaced2:Boolean=false;
for (var i:int=0; i0&&cutAngle<=Math.PI) {
if (currentPoly==2) {
cutPlaced1=true;
newPolyVertices1.push(point);
newPolyVertices1.push(entryPoint[fixtureIndex]);
}
newPolyVertices1.push(worldPoint);
currentPoly=1;
}
else {
if (currentPoly==1) {
cutPlaced2=true;
newPolyVertices2.push(entryPoint[fixtureIndex]);
newPolyVertices2.push(point);
}
newPolyVertices2.push(worldPoint);
currentPoly=2;
}
}
if (! cutPlaced1) {
newPolyVertices1.push(point);
newPolyVertices1.push(entryPoint[fixtureIndex]);
}
if (! cutPlaced2) {
newPolyVertices2.push(entryPoint[fixtureIndex]);
newPolyVertices2.push(point);
}
createSlice(newPolyVertices1,newPolyVertices1.length);
createSlice(newPolyVertices2,newPolyVertices2.length);
world.DestroyBody(affectedBody);
}
return 1;
}
private function findCentroid(vs:Vector., count:uint):b2Vec2 {
var c:b2Vec2 = new b2Vec2();
var area:Number=0.0;
var p1X:Number=0.0;
var p1Y:Number=0.0;
var inv3:Number=1.0/3.0;
for (var i:int = 0; i < count; ++i) {
var p2:b2Vec2=vs[i];
var p3:b2Vec2=i+1,numVertices:int):void {
var centre:b2Vec2=findCentroid(vertices,vertices.length);
for (var i:int=0; i
I hope this will suggest some interesting gameplay features. No need to download anything, just copy/paste the code in the slicing example.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.