/**
* Copyright Yukulele ( http://wonderfl.net/user/Yukulele )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/n9mF
*/
package {
import adobe.utils.ProductManager;
import Box2D.Dynamics.Joints.b2DistanceJointDef;
import Box2D.Dynamics.Joints.b2JointDef;
import Box2D.Dynamics.Joints.b2JointEdge;
import Box2D.Dynamics.Joints.b2MouseJoint;
import Box2D.Dynamics.Joints.b2MouseJointDef;
import Box2D.Dynamics.Joints.b2RevoluteJointDef;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import flash.utils.getTimer;
import net.hires.debug.Stats;
[SWF(backgroundColor=0x000000,frameRate=40)]
public class Main extends Sprite {
private var the_world:b2World;
private var timerOld:int;
private var time_count:Timer = new Timer(100);
private var mouseJoint:b2MouseJoint;
private var mousePVec:b2Vec2 = new b2Vec2();
private var myBoundaryListener:BoundaryListener = new BoundaryListener();
private const echelle:Number = 10;
public function Main() {
stage.frameRate = 40;
timerOld = getTimer();
var environment:b2AABB = new b2AABB();
environment.lowerBound.Set(0, 0);
environment.upperBound.Set(46, 46);
var gravity:b2Vec2=new b2Vec2(0.0,9.81);
the_world=new b2World(environment,gravity,false);
var debug_draw:b2DebugDraw = new b2DebugDraw();
var debug_sprite:Sprite = new Sprite();
addChild(debug_sprite);
debug_draw.m_sprite=debug_sprite;
debug_draw.m_drawScale=echelle;
debug_draw.m_fillAlpha = 0.5;
debug_draw.m_lineThickness=0;
debug_draw.m_drawFlags =
//b2DebugDraw.e_aabbBit|
//b2DebugDraw.e_centerOfMassBit|
//b2DebugDraw.e_coreShapeBit|
b2DebugDraw.e_jointBit|
//b2DebugDraw.e_obbBit|
//b2DebugDraw.e_pairBit|
b2DebugDraw.e_shapeBit |
0;
the_world.SetDebugDraw(debug_draw);
the_world.m_allowSleep = true;
var nbr:int = 9;
var rayon:Number = .5;
/*for (var i:int = 0; i < nbr; i++)
{
var x:Number = 8.25+(i - nbr / 2) * rayon*2;
var cercle:b2Body = cree_cercle(x, 9, rayon * 1);
var jointDist:b2DistanceJointDef = new b2DistanceJointDef();
jointDist.Initialize(final_body, cercle, new b2Vec2(x, 3.5), cercle.GetWorldCenter());
jointDist.frequencyHz = 0;
//jointDist.length = 2;
jointDist.collideConnected = true;
the_world.CreateJoint(jointDist);
} */
var i:int;
cree_polygone(
{
x:[ 0, 0,46,46,0,1,45,45, 1, 1],
y:[ 0,46,46, 0, 0, 1, 1,45,45, 1]
},0,0,true);
cree_polygone(
{
x:[0,2,1,1,4,4,3,5,5,0],
y:[4,4,3,1,1,3,4,4,0,0]
},7, 5);
cree_polygone(
{
x:[0,-2,-1,-1,-4,-4,-3,-5,-5,0],
y:[-4,-4,-3,-1,-1,-3,-4,-4,0,0]
},12,15);
cree_polygone(
{
x:[1,2,2,1,2.5,4,3,3,4,2.5],
y:[2,3,7,8,7.5,8,7,3,2,2.5]
},7, 5);
/////////
cree_polygone(
{
x:[0,2,1,1,4,4,3,5,5,0],
y:[4,4,3,1,1,3,4,4,0,0]
},17, 5);
cree_polygone(
{
x:[0,-2,-1,-1,-4,-4,-3,-5,-5,0],
y:[-4,-4,-3,-1,-1,-3,-4,-4,0,0]
},22,15);
cree_polygone(
{
x:[1.5,2,2,1.5,2.5,3.5,3,3,3.5,2.5],
y:[2,3,7,8,7.5,8,7,3,2,2.5]
},17, 5);
/*cree_polygone(
{
x:[1.02,2.02,2.02,2.98,2.98,3.98,2.5],
y:[2,3,4,4,3,2,2.5]
},7, 5);*/
/*
for (i = 0; i < 10; i++)
{
cree_polygone(
{
x:[0,-0.75,0,1,0.25,1],
y:[0,0.5,1,1,.5,0]
},i+20,5);
}
*/
/*
for (i = 0; i < 7; i++)
for (var j:int = 0; j < 7; j++)
{
cree_polygone(
{
x:[0,0,1,1],
y:[(j%2)*.4,(j%2)*.6+.4,((j+1)%2)*.6+.4,((j+1)%2)*.4]
},j+15,i+10);
}*/
the_world.SetBoundaryListener(myBoundaryListener);
addEventListener(Event.ENTER_FRAME, on_enter_frame);
time_count.addEventListener(TimerEvent.TIMER, on_time);
//time_count.start();
//addChild(new Stats);
stage.addEventListener(MouseEvent.MOUSE_DOWN, createMouse);
stage.addEventListener(MouseEvent.MOUSE_UP, destroyMouse);
}
private function cree_polygone(points:Object, x:Number = 0, y:Number = 0, fixe:Boolean = false):b2Body
{
var poly:Array=Triangulator.polygonizeTriangles(Triangulator.triangulatePolygonFromFlatArray(points.x, points.y));
trace(poly);
var bodydef:b2BodyDef = new b2BodyDef();
bodydef.position.Set(x, y);
bodydef.isBullet = true;
var body:b2Body = the_world.CreateBody(bodydef);
for (var i:int = 0; i < poly.length-1 ; i++)
{
var p:Polygon = poly[i];
var b2poly:b2PolygonDef = new b2PolygonDef();
b2poly.friction = .5;
b2poly.restitution = .4;
if(!fixe)
b2poly.density = 100;
b2poly.vertexCount = p.nVertices;
for (var j:int = 0; j < p.nVertices; j++)
{
b2poly.vertices[j].Set(p.x[j], p.y[j]);
}
body.CreateShape(b2poly);
}
body.SetMassFromShapes();
return body;
}
private function on_time(e:Event):void {
creePoly();
}//er war schone wenn wir freunde gebleiben waren
private function creePoly():void
{
var final_body:b2Body;
var the_body:b2BodyDef;
the_body = new b2BodyDef();
the_body.position.Set(7.75/*Math.random() * 17*/, -5);
the_body.angle = Math.random() * 6;
var the_box:b2PolygonDef;
the_box = new b2PolygonDef();
var nbrangle:int = Math.floor(3+Math.random()*5);
var rayon:Number = Math.random()+.2;
the_box.vertexCount = nbrangle;
for (var i:int = 0; i < nbrangle; i++)
{
the_box.vertices[i]=new b2Vec2((Math.cos(2*Math.PI*i/nbrangle)+(Math.random()-.5)*.3)*rayon, (Math.sin(2*Math.PI*i/nbrangle)+(Math.random()-.5)*.3)*rayon);
}
the_box.isSensor
the_box.restitution = .5;
the_box.friction = .5;
the_box.density = 100;
final_body = the_world.CreateBody(the_body);
final_body.SetAngularVelocity((Math.random() - .5) * 16);
final_body.SetLinearVelocity(new b2Vec2((Math.random() - .5) * 10, 0));
final_body.CreateShape(the_box);
final_body.SetMassFromShapes();
}
private var temps:int;
private function on_enter_frame(e:Event):void {
temps = getTimer() - timerOld;
timerOld = getTimer();
the_world.Step(temps/1000, 30);
//the_world.Step(1/stage.frameRate, 30);
myBoundaryListener.lastBodys().forEach(function(elm:b2Body, num:int, vect:Vector.<b2Body>):void {
var joint:b2JointEdge = elm.GetJointList();
while(joint)
{
if (joint.joint == mouseJoint)
mouseJoint = null;
the_world.DestroyJoint(joint.joint);
joint = joint.next;
}
the_world.DestroyBody(elm);
});
/*
var the_body:b2Body = the_world.GetBodyList();
var next:b2Body;
while(the_body)
{
next = the_body.GetNext();
if (the_body.GetPosition().y > 17 || the_body.GetPosition().x < -2||the_body.GetPosition().x > 17.5)
{
var joint:b2JointEdge = the_body.GetJointList();
while(joint)
{
the_world.DestroyJoint(joint.joint);
joint = joint.next;
}
the_world.DestroyBody(the_body);
}
the_body = next;
}
*/
if (mouseJoint) {
var mouseXWorldPhys:Number=mouseX/echelle;
var mouseYWorldPhys:Number=mouseY/echelle;
var p2:b2Vec2=new b2Vec2(mouseXWorldPhys,mouseYWorldPhys);
mouseJoint.SetTarget(p2);
}
}
public function createMouse(evt:MouseEvent):void {
var body:b2Body=GetBodyAtMouse();
if (body) {
var mouseJointDef:b2MouseJointDef=new b2MouseJointDef ;
mouseJointDef.body1=the_world.GetGroundBody();
mouseJointDef.body2=body;
mouseJointDef.target.Set(mouseX/echelle, mouseY/echelle);
mouseJointDef.maxForce=100000;
mouseJointDef.timeStep=temps/1000;
mouseJoint=the_world.CreateJoint(mouseJointDef) as b2MouseJoint;
}
}
public function destroyMouse(evt:MouseEvent=null):void {
if (mouseJoint) {
the_world.DestroyJoint(mouseJoint);
mouseJoint=null;
}
}
public function GetBodyAtMouse(includeStatic:Boolean=false):b2Body {
var mouseXWorldPhys:Number = (mouseX)/echelle;
var mouseYWorldPhys:Number = (mouseY)/echelle;
mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys);
var aabb:b2AABB = new b2AABB();
aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
var k_maxCount:int=10;
var shapes:Array = new Array();
var count:int=the_world.Query(aabb,shapes,k_maxCount);
var body:b2Body=null;
for (var i:int = 0; i < count; ++i) {
if (shapes[i].GetBody().IsStatic()==false||includeStatic) {
var tShape:b2Shape=shapes[i] as b2Shape;
var inside:Boolean=tShape.TestPoint(tShape.GetBody().GetXForm(),mousePVec);
if (inside) {
body=tShape.GetBody();
break;
}
}
}
return body;
}
}
}
import Box2D.Dynamics.b2BoundaryListener;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2World;
class BoundaryListener extends b2BoundaryListener
{
private var bodys:Vector.<b2Body>;
public function BoundaryListener()
{
bodys = new Vector.<b2Body>;
}
public override function Violation(body:b2Body):void
{
bodys.push(body);
}
public function lastBodys():Vector.<b2Body>
{
var bodys2:Vector.<b2Body> = bodys;
bodys = new Vector.<b2Body>;
return bodys2;
}
}
import flash.geom.Point;
class Triangulator {
public function Triangulator()
{
}
/* give it an array of points (vertexes)
* returns an array of Triangles
* */
public static function triangulatePolygon(v:Array):Array
{
var xA:Array = new Array();
var yA:Array = new Array();
for each(var p:Point in v) {
xA.push(p.x);
yA.push(p.y);
}
return(triangulatePolygonFromFlatArray(xA, yA));
}
/* give it a list of vertexes as flat arrays
* returns an array of Triangles
* */
public static function triangulatePolygonFromFlatArray(xv:Array, yv:Array):Array
{
if (xv.length < 3 || yv.length < 3 || yv.length != xv.length) {
trace("Please make sure both arrays or of the same length and have at least 3 vertices in them!");
return null;
}
var i:int = 0;
var vNum:int = xv.length;
var buffer:Array = new Array();
var bufferSize:int = 0;
var xrem:Array = new Array();
var yrem:Array = new Array();
for (i = 0; i < vNum; ++i) {
xrem[i] = xv[i];
yrem[i] = yv[i];
}
while (vNum > 3){
//Find an ear
var earIndex:int = -1;
for (i = 0; i < vNum; ++i) {
if (isEar(i, xrem, yrem)) {
earIndex = i;
break;
}
}
//If we still haven't found an ear, we're screwed.
//The user did Something Bad, so return null.
//This will probably crash their program, since
//they won't bother to check the return value.
//At this we shall laugh, heartily and with great gusto.
if (earIndex == -1) {
trace('no ear found');
return null;
}
//Clip off the ear:
// - remove the ear tip from the list
//Opt note: actually creates a new list, maybe
//this should be done in-place instead. A linked
//list would be even better to avoid array-fu.
--vNum;
var newx:Array = new Array();
var newy:Array = new Array();
var currDest:int = 0;
for (i = 0; i < vNum; ++i) {
if (currDest == earIndex) ++currDest;
newx[i] = xrem[currDest];
newy[i] = yrem[currDest];
++currDest;
}
// - add the clipped triangle to the triangle list
var under:int = (earIndex == 0)?(xrem.length - 1):(earIndex - 1);
var over:int = (earIndex == xrem.length - 1)?0:(earIndex + 1);
var toAdd:Triangle = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under], yrem[under]);
buffer[bufferSize] = toAdd;
++bufferSize;
// - replace the old list with the new one
xrem = newx;
yrem = newy;
}
var toAddMore:Triangle = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);
buffer[bufferSize] = toAddMore;
++bufferSize;
var res:Array = new Array();
for (i = 0; i < bufferSize; i++) {
res[i] = buffer[i];
}
return res;
}
/* takes: array of Triangles
* returns: array of Polygons
* */
public static function polygonizeTriangles(triangulated:Array):Array
{
var polys:Array;
var polyIndex:int = 0;
var i:int = 0;
if (triangulated == null){
return null;
} else {
polys = new Array();
var covered:Array = new Array();
for (i = 0; i < triangulated.length; i++) {
covered[i] = false;
}
var notDone:Boolean = true;
while(notDone){
var currTri:int = -1;
for (i = 0; i < triangulated.length; i++) {
if (covered[i]) continue;
currTri = i;
break;
}
if (currTri == -1){
notDone = false;
} else{
var poly:Polygon = new Polygon(triangulated[currTri].x, triangulated[currTri].y);
covered[currTri] = true;
for (i = 0; i < triangulated.length; i++) {
if (covered[i]) continue;
var newP:Polygon = poly.add(triangulated[i]);
if (newP == null) continue;
if (newP.isConvex()){
poly = newP;
covered[i] = true;
}
}
}
polys[polyIndex] = poly;
polyIndex++;
}
}
var ret:Array = new Array();
for (i = 0; i < polyIndex; i++) {
ret[i] = polys[i];
}
return ret;
}
//Checks if vertex i is the tip of an ear
/*
* */
public static function isEar(i:int, xv:Array, yv:Array):Boolean
{
var dx0:Number, dy0:Number, dx1:Number, dy1:Number;
dx0 = dy0 = dx1 = dy1 = 0;
if (i >= xv.length || i < 0 || xv.length < 3) {
return false;
}
var upper:int = i + 1;
var lower:int = i - 1;
if (i == 0){
dx0 = xv[0] - xv[xv.length - 1];
dy0 = yv[0] - yv[yv.length - 1];
dx1 = xv[1] - xv[0];
dy1 = yv[1] - yv[0];
lower = xv.length - 1;
} else if (i == xv.length - 1) {
dx0 = xv[i] - xv[i - 1];
dy0 = yv[i] - yv[i - 1];
dx1 = xv[0] - xv[i];
dy1 = yv[0] - yv[i];
upper = 0;
} else{
dx0 = xv[i] - xv[i - 1];
dy0 = yv[i] - yv[i - 1];
dx1 = xv[i + 1] - xv[i];
dy1 = yv[i + 1] - yv[i];
}
var cross:Number = (dx0*dy1)-(dx1*dy0);
if (cross > 0) return false;
var myTri:Triangle = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]);
for (var j:int = 0; j < xv.length; ++j) {
if (!(j == i || j == lower || j == upper)) {
if (myTri.isInside(xv[j], yv[j])) return false;
}
}
return true;
}
}
class Triangle {
public var x:Array = new Array();
public var y:Array = new Array();
public function Triangle(x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number) {
var dx1:Number = x2-x1;
var dx2:Number = x3-x1;
var dy1:Number = y2-y1;
var dy2:Number = y3-y1;
var cross:Number = (dx1*dy2)-(dx2*dy1);
var ccw:Boolean = (cross>0);
if (ccw){
x[0] = x1; x[1] = x2; x[2] = x3;
y[0] = y1; y[1] = y2; y[2] = y3;
} else{
x[0] = x1; x[1] = x3; x[2] = x2;
y[0] = y1; y[1] = y3; y[2] = y2;
}
}
public function isInside(_x:Number, _y:Number):Boolean{
var vx2:Number = _x - x[0]; var vy2:Number = _y - y[0];
var vx1:Number = x[1] - x[0]; var vy1:Number = y[1] - y[0];
var vx0:Number = x[2] - x[0]; var vy0:Number = y[2] - y[0];
var dot00:Number = vx0 * vx0 + vy0 * vy0;
var dot01:Number = vx0 * vx1 + vy0 * vy1;
var dot02:Number = vx0 * vx2 + vy0 * vy2;
var dot11:Number = vx1 * vx1 + vy1 * vy1;
var dot12:Number = vx1 * vx2 + vy1 * vy2;
var invDenom:Number = 1.0 / (dot00 * dot11 - dot01 * dot01);
var u:Number = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v:Number = (dot00 * dot12 - dot01 * dot02) * invDenom;
return ((u > 0) && (v > 0) && (u + v < 1));
}
}
class Polygon {
public var nVertices:int;
public var x:Array = new Array();
public var y:Array = new Array();
public function Polygon(_x:Array, _y:Array = null)
{
if(_y == null) {
_y = _x.y;
_x = _x.x;
}
nVertices = _x.length;
for (var i:int = 0; i < nVertices; ++i) {
x[i] = _x[i];
y[i] = _y[i];
}
}
public function set(p:Polygon):void
{
nVertices = p.nVertices;
x = new Array();
y = new Array();
for (var i:int = 0; i < nVertices; ++i) {
x[i] = p.x[i];
y[i] = p.y[i];
}
}
/*
* Assuming the polygon is simple, checks
* if it is convex.
*/
public function isConvex():Boolean
{
var isPositive:Boolean = false;
for (var i:int = 0; i < nVertices; ++i) {
var lower:int = (i == 0)?(nVertices - 1):(i - 1);
var middle:int = i;
var upper:int = (i == nVertices - 1)?(0):(i + 1);
var dx0:Number = x[middle] - x[lower];
var dy0:Number = y[middle] - y[lower];
var dx1:Number = x[upper]-x[middle];
var dy1:Number = y[upper]-y[middle];
var cross:Number = dx0 * dy1 - dx1 * dy0;
//Cross product should have same sign
//for each vertex if poly is convex.
var newIsP:Boolean = (cross>0)?true:false;
if (i == 0) {
isPositive = newIsP;
} else if (isPositive != newIsP){
return false;
}
}
return true;
}
/*
* Tries to add a triangle to the polygon.
* Returns null if it can't connect properly.
* Assumes bitwise equality of join vertices.
*/
public function add(t:Triangle):Polygon
{
//First, find vertices that connect
var firstP:int = -1;
var firstT:int = -1;
var secondP:int = -1;
var secondT:int = -1;
var i:int = 0;
for (i = 0; i < nVertices; i++) {
if (t.x[0] == this.x[i] && t.y[0] == this.y[i]){
if (firstP == -1){
firstP = i; firstT = 0;
} else{
secondP = i; secondT = 0;
}
} else if (t.x[1] == this.x[i] && t.y[1] == this.y[i]) {
if (firstP == -1){
firstP = i; firstT = 1;
} else{
secondP = i; secondT = 1;
}
} else if (t.x[2] == this.x[i] && t.y[2] == this.y[i]){
if (firstP == -1){
firstP = i; firstT = 2;
} else{
secondP = i; secondT = 2;
}
} else {
//println(t.x[0]+" "+t.y[0]+" "+t.x[1]+" "+t.y[1]+" "+t.x[2]+" "+t.y[2]);
//println(x[0]+" "+y[0]+" "+x[1]+" "+y[1]);
}
}
//Fix ordering if first should be last vertex of poly
if (firstP == 0 && secondP == nVertices - 1) {
firstP = nVertices-1;
secondP = 0;
}
//Didn't find it
if (secondP == -1) return null;
//Find tip index on triangle
var tipT:int = 0;
if (tipT == firstT || tipT == secondT) tipT = 1;
if (tipT == firstT || tipT == secondT) tipT = 2;
var newx:Array = new Array();
var newy:Array = new Array();
var currOut:int = 0;
for (i = 0; i < nVertices; i++) {
newx[currOut] = x[i];
newy[currOut] = y[i];
if (i == firstP){
++currOut;
newx[currOut] = t.x[tipT];
newy[currOut] = t.y[tipT];
}
++currOut;
}
return new Polygon(newx, newy);
}
public function toString():String
{
var string:String = "\n[Polygon:";
for (var i:int = 0; i < this.nVertices; i++)
{
string += "\n ["+this.x[i]+"\t"+this.y[i]+"],";
}
return string+"]";
}
}