WEB开发网
开发学院图形图像Flash The engine behind Splitter Flash game – first... 阅读

The engine behind Splitter Flash game – first AS3 prototype

 2009-10-31 00:00:00 来源:WEB开发网   
核心提示:Some time ago I posted about the engine behind Splitter Flash game, the C code used to cut off and split objects with Box2DNow I received an AS3 prototype from

Some time ago I posted about the engine behind Splitter Flash game, the C code used to cut off and split objects with Box2D

Now I received an AS3 prototype from Guillaume Pommey.

Hi ! I try to port the splitter engine to AS3, I haven’t any error in the function but I have an incorrect structure…

Can you help me, the port may be correct…

PS : The Box2D files are changed, because I use a funtion (raycast) which isn’t in the original source. There isn’t the key controls, there are useless if the programm doesn’t work. The problem should be come the structure and the end of the programme with the function Step or Test.

As you can see, Guillaume used raycast function you can find at this link (also take a look at the demo, it’s very interesting).

This is the source code:

package{
 
import Box2D.Dynamics.*
import Box2D.Collision.*
import Box2D.Collision.Shapes.*
import Box2D.Dynamics.Joints.*
import Box2D.Dynamics.Contacts.*
import Box2D.Common.Math.*
import Box2D.Common.*
import flash.events.Event;
import flash.display.*;
import flash.text.*;
import General.*
import flash.display.MovieClip;
 
 public class splitter extends MovieClip{ //Public Class
  public function splitter(){ //Main function
 
   var m_sprite:Sprite = new Sprite();
   addChild(m_sprite);
 
   addEventListener(Event.ENTER_FRAME, update, false, 0, true);
 
   var worldAABB:b2AABB = new b2AABB();
   worldAABB.lowerBound.Set(-1000.0, -1000.0);
   worldAABB.upperBound.Set(1000.0, 1000.0);
 
   // Define the gravity vector
   var gravity:b2Vec2 = new b2Vec2(0.0, 0.9);
 
   // Allow bodies to sleep
   var doSleep:Boolean = true;
 
   // Construct a world object
   m_world = new b2World(worldAABB, gravity, doSleep);
   dbgDraw = new b2DebugDraw();
   dbgDraw.m_sprite = m_sprite;
   dbgDraw.m_drawScale = 15.0;
   dbgDraw.m_fillAlpha = 0.3;
   dbgDraw.m_lineThickness = 1.0;
   dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
   m_world.SetDebugDraw(dbgDraw);
 
   CutterTest();
 
  }
 
 
  public function CutterTest(){
 
   //m_world->SetGravity(b2Vec2(0,0));
 
     var ground:b2Body = null;
 
     var bd:b2BodyDef = new b2BodyDef();
     bd.position.Set(0.0, -10.0);
     ground = m_world.CreateBody(bd);
 
     var sd:b2PolygonDef = new b2PolygonDef();
     sd.SetAsBox(50.0, 10.0);
     ground.CreateShape(sd);
 
     bd.position.Set(0.0, 30);
     ground = m_world.CreateBody(bd);
 
     sd.SetAsBox(50.0, 10.0);
     ground.CreateShape(sd);
 
     bd.position.Set(0.0, 1.0);
     laserBody = m_world.CreateBody(bd);
 
     sd.SetAsBox(5.0, 1.0);
     sd.density = 4.0;
     laserBody.CreateShape(sd);
     laserBody.SetMassFromShapes();
 
     sd.SetAsBox(3.0, 3.0);
     sd.density = 5.0;
 
     bd.userData = 1;
     bd.position.Set(0.0, 8.0);
     var body1:b2Body = m_world.CreateBody(bd);
     body1.CreateShape(sd);
     body1.SetMassFromShapes();
 
     sd.SetAsBox(3.0, 3.0);
     sd.density = 5.0;
 
     bd.userData = 1;
     bd.position.Set(0.0, 8.0);
     body1 = m_world.CreateBody(bd);
     body1.CreateShape(sd);
     body1.SetMassFromShapes();
  }
 
  /***************************************************/
  /*********************ETAPE 1***********************/
  /***************************************************/
 
  public function CheckPolyShape(poly)
  {
   if (!(3 <= poly.vertexCount && poly.vertexCount <= b2_maxPolygonVertices)){
     return -1;
   }
 
   var m_normals:b2Vec2 = new b2Vec2(poly.vertexCount);
 
    // Compute normals. Ensure the edges have non-zero length.
    for (var i=0; i < poly.vertexCount; i++)
    {
     var i1 = i;
     var i2 = 0;
     if((i + 1) < poly.vertexCount){//Possible erreur
      i2 = i + 1;
     } else {
      i2 = 0;
     }
     //var i2 = i + 1 <poly->vertexCount ? i + 1 : 0;
     var edge:b2Vec2 = new b2Vec2(poly.vertices[i2] - poly.vertices[i1]);
     if (!(edge.LengthSquared()> Number.MIN_VALUE * Number.MIN_VALUE))//Peut être une erreur
      return -1;
     m_normals[i] = b2Math.b2CrossVF(edge, 1.0);//Problème ???
     m_normals[i].Normalize();
    }
 
    // Ensure the polygon is convex.
    for (i=0; i <poly.vertexCount; i++)
    {
     for (var j=0; j <poly.vertexCount; j++)
     {
      // Don't check vertices on the current edge.
      if (j == i || j == (i + 1) % poly.vertexCount)
      {
       continue;
      }
 
      // Your polygon is non-convex (it has an indentation).
      // Or your polygon is too skinny.
      var vecPlus = poly.vertices[j] - poly.vertices[i];
      var s = b2Math.b2Dot(m_normals[i], vecPlus);//Problème ??
      if (!(s < -b2Settings.b2_linearSlop)){//Idem
       return -1;
      }
     }
    }
 
    // Ensure the polygon is counter-clockwise.
    for (i=1; i <poly.vertexCount; i++)
    {
     var cross = b2Math.b2CrossVV(m_normals[i-1], m_normals[i]);
 
     // Keep asinf happy.
     cross = b2Math.b2Clamp(cross, -1.0, 1.0);
 
     // You have consecutive edges that are almost parallel on your polygon.
     var angle = Math.asin(cross);
     if (!(angle> b2Settings.b2_angularSlop))
      return -1;
    }
 
    // Compute the polygon centroid.
    var m_centroid:b2Vec2; 
    m_centroid.Set(0.0, 0.0);
    var area = 0.0;
 
    // pRef is the reference point for forming triangles.
    // It's location doesn't change the result (except for rounding error).
    var pRef:b2Vec2 = new b2Vec2(0.0, 0.0);
 
    const inv3 = 1.0 / 3.0;
 
    for (i=0; i <poly.vertexCount; i++)
    {
     // Triangle vertices.
     var p1:b2Vec2 =  pRef;
     var p2:b2Vec2 = new b2Vec2(poly.vertices[i]);
     var p3 = 0;
     if((i + 1) < poly.vertexCount){//Possible erreur
      p3 = poly.vertices[i+1];
     } else {
      p3 = poly.vertices[0];
     }
     //var p3:b2Vec2 = i + 1 <poly->vertexCount ? poly->vertices[i+1] : poly->vertices[0];
 
     //var e1Vec:b2Vec2 = (p2 - p1)
     var e1:b2Vec2 = b2Math.SubtractVV(p2, p1);// ?????
     var e2:b2Vec2 = b2Math.SubtractVV(p3, p1);// ?????
 
     var D = b2Math.b2CrossVV(e1, e2);
 
     var triangleArea = 0.5 * D;
     area += triangleArea;
 
     // Area weighted centroid
     m_centroid += triangleArea * inv3 * (p1 + p2 + p3);
    }
 
    // Centroid
    if (!(area> Number.MIN_VALUE))
     return -1;
    //m_centroid *= 1.0 / area;
    b2Math.MulFV((1.0 / area), m_centroid); // ??????
 
    // Compute the oriented bounding box.
    //ComputeOBB(&m_obb, m_vertices, m_vertexCount);
 
    // Create core polygon shape by shifting edges inward.
    // Also compute the min/max radius for CCD.
    for (i=0; i <poly.vertexCount; i++)
    {
     //Possible erreur
     if((i - 1) >= 0){
      i1 = i - 1;
     }else {
      i1 = (poly.vertexCount - 1)
     }
     //int32 i1 = i - 1>= 0 ? i - 1 : poly->vertexCount - 1;
     i2 = i;
 
     var n1:b2Vec2 = new b2Vec2(m_normals[i1]);
     var n2:b2Vec2 = new b2Vec2(m_normals[i2]);
     var v:b2Vec2 = b2Math.SubtractVV(poly.vertices[i], m_centroid); // ?????
 
     var d:b2Vec2;
     d.x = b2Math.b2Dot(n1, v) - b2Settings.b2_toiSlop;
     d.y = b2Math.b2Dot(n2, v) - b2Settings.b2_toiSlop;
 
     // Shifting the edge inward by b2_toiSlop should
     // not cause the plane to pass the centroid.
 
     // Your shape has a radius/extent less than b2_toiSlop.
     if (!(d.x>= 0.0))
      return -1;
     if (!(d.y>= 0.0))
      return -1;
    }
 
 
   return 0;
 
  }
 
 /***************************************************/
 /*********************ETAPE 2***********************/
 /***************************************************/
 
  /// Split a shape trough a segment
    /// @return
    /// -1 - Error on split
    ///  0 - Normal result is two new shape definitions.
    public function SplitShape(shape, segment, splitSize, newPolygon)// ????
    {
        /*assert(shape != NULL);
        assert(newPolygon != NULL);
        assert(splitSize>= 0);*/ // Eventuellement utile...mais bon
 
      var lambda:Number = 1;
        var normal:b2Vec2;
 
  const b:b2Body = shape.GetBody();
       //const b2Body* b = shape->GetBody();
        const xf:b2XForm = b.GetXForm();
        if (shape.TestSegment(xf, lambda, normal, segment, 1.0) != e_hitCollide)
            return -1;
  var nextVec = (1-lambda)*segment.p1+lambda*segment.p2;
        var entryPoint:b2Vec2 = nextVec;
 
        var reverseSegment:b2Segment;
        reverseSegment.p1 = segment.p2;
        reverseSegment.p2 = segment.p1;
 
        if (shape.TestSegment(xf, lambda, normal, reverseSegment, 1.0) != e_hitCollide)
            return -1;
  var nextVec2 = (1-lambda)*segment.p2+lambda*segment.p1;//Clash ??
        var exitPoint:b2Vec2 = nextVec2;
 
        var localEntryPoint:b2Vec2 = b.GetLocalPoint(entryPoint);
        var localExitPoint:b2Vec2  = b.GetLocalPoint(exitPoint);
        const vertices:b2Vec2 = shape.GetVertices();
        var cutAdded:Array = [-1,-1];
        var lastA = -1;
        for(var i = 0; i<shape.GetVertexCount(); i++)
        {
            var n;
            //Find out if this vertex is on the old or new shape.
            if (b2Math.b2Dot(b2Math.b2CrossVF(b2Math.SubtractVV(localExitPoint,localEntryPoint), 1), b2Math.SubtractVV(vertices[i], localEntryPoint))> 0) //Clash ??
                n = 0;
            else
                n = 1;
            if (lastA != n)
            {
                //If we switch from one shape to the other add the cut vertices.
                if (lastA == 0)
                {
                    //assert(cutAdded[0] == -1); Couiiic
                    cutAdded[0] = newPolygon[lastA].vertexCount;
                    newPolygon[lastA].vertices[newPolygon[lastA].vertexCount] = localExitPoint;
                    newPolygon[lastA].vertexCount++;
                    newPolygon[lastA].vertices[newPolygon[lastA].vertexCount] = localEntryPoint;
                    newPolygon[lastA].vertexCount++;
                }
                if (lastA == 1)
                {
                    //assert(cutAdded[lastA] == -1); Recouiiic
                    cutAdded[lastA] = newPolygon[lastA].vertexCount;
                    newPolygon[lastA].vertices[newPolygon[lastA].vertexCount] = localEntryPoint;
                    newPolygon[lastA].vertexCount++;
                    newPolygon[lastA].vertices[newPolygon[lastA].vertexCount] = localExitPoint;
                    newPolygon[lastA].vertexCount++;
                }
            }
            newPolygon[n].vertices[newPolygon[n].vertexCount] = vertices[i];
            newPolygon[n].vertexCount++;
            lastA = n;
        }
 
        //Add the cut in case it has not been added yet.
        if (cutAdded[0] == -1)
        {
            cutAdded[0] = newPolygon[0].vertexCount;
            newPolygon[0].vertices[newPolygon[0].vertexCount] = localExitPoint;
            newPolygon[0].vertexCount++;
            newPolygon[0].vertices[newPolygon[0].vertexCount] = localEntryPoint;
            newPolygon[0].vertexCount++;
        }
        if (cutAdded[1] == -1)
        {
            cutAdded[1] = newPolygon[1].vertexCount;
            newPolygon[1].vertices[newPolygon[1].vertexCount] = localEntryPoint;
            newPolygon[1].vertexCount++;
            newPolygon[1].vertices[newPolygon[1].vertexCount] = localExitPoint;
            newPolygon[1].vertexCount++;
        }
 
        for(n = 0; n<2 ; n++)
        {
            var offset:b2Vec2;
            if (cutAdded[n]> 0)
            {
    var offsetValue = (newPolygon[n].vertices[cutAdded[n]-1] - newPolygon[n].vertices[cutAdded[n]])//Substitution
                offset = offsetValue;
            }else{
    offsetValue = (newPolygon[n].vertices[newPolygon[n].vertexCount-1] - newPolygon[n].vertices[0]);//Substitution
                offset = offsetValue;
            }
            offset.Normalize();
 
            newPolygon[n].vertices[cutAdded[n]] += b2Math.MulFV(splitSize, offset);
 
 
            if (cutAdded[n] <newPolygon[n].vertexCount-2)
            {
    offsetValue = (newPolygon[n].vertices[cutAdded[n]+2] - newPolygon[n].vertices[cutAdded[n]+1]);
                offset = offsetValue;
            }else{
    offsetValue = (newPolygon[n].vertices[0] - newPolygon[n].vertices[newPolygon[n].vertexCount-1]);
                offset = offsetValue;
            }
            offset.Normalize();
 
            newPolygon[n].vertices[cutAdded[n]+1] += b2Math.MulFV(splitSize, offset);
        }
 
        /*
        //Check if the new shapes are not too tiny. (TODO: still generates shapes which fail assert checks)
        for(int n=0;n<2;n++)
            for(int i=0;i<newPolygon[n].vertexCount;i++)
                for(int j=0;j<newPolygon[n].vertexCount;j++)
                    if (i != j && (newPolygon[n].vertices[i] - newPolygon[n].vertices[j]).Length() <0.1)
                        return -1;
        */
        for(n=0;n<2;n++)
            if (CheckPolyShape(newPolygon[n]))
                return -1;
        return 0;
    }
 
 /***************************************************/
 /*********************ETAPE 3***********************/
 /***************************************************/
 
 public function Cut():void
    {
        var segmentLength = 30.0;
 
        var segment:b2Segment;
 
        var laserStart:b2Vec2 = new b2Vec2(5.0-0.1, 0.0);
        var laserDir:b2Vec2 = new b2Vec2(segmentLength, 0.0);
 
        segment.p1 = laserBody.GetWorldPoint(laserStart);
        segment.p2 = segment.p1 + laserBody.GetWorldVector(laserDir);
 
        var max_shapes = 64;
      var shapes:b2Shape; 
  var count = 1;
        count = m_world.Raycast(segment, shapes[0], max_shapes, false, null);//Gros doute !!
        for(var i=0;i<count;i++)
        {
            //Make sure it's a polygon, we cannot cut circles.
            if(shapes[i].GetType() != b2Shape.e_polygonShape)
                continue;
 
            var b:b2Body = shapes[i].GetBody();
            //Custom check to make sure we don't cut stuff we don't want to cut.
            if (b.GetUserData() != 1) //Ouille !
                continue;//return if we cannot pass trough uncutable shapes.
 
            var polyShape:b2PolygonShape = new b2PolygonShape(shapes[i]);
            var pd:b2PolygonDef;
            pd[0].density = 5.0;
            pd[1].density = 5.0;
 
            if (SplitShape(polyShape, segment, 0.1, pd) == 0)
            {
                b.DestroyShape(shapes[i]);
                b.CreateShape(pd[0]);
                b.SetMassFromShapes();
                b.WakeUp();
 
                var bd:b2BodyDef;
                bd.userData = 1;
                bd.position = b.GetPosition();
                bd.angle = b.GetAngle();
                var newBody:b2Body = m_world.CreateBody(bd);
                newBody.CreateShape(pd[1]);
                newBody.SetMassFromShapes();
                newBody.SetAngularVelocity(b.GetAngularVelocity());
                newBody.SetLinearVelocity(b.GetLinearVelocity());
            }
        }
    }
 
 public function Step(Settings:*, settings)
    {
      /*  m_debugDraw.DrawString(5, m_textLine, "Keys: cut = c");
        m_textLine += 15;*/
 
        //Test::Step(settings);
 
        var segmentLength = 30.0;
 
        var segment:b2Segment;
        var laserStart:b2Vec2 = new b2Vec2(5.0-0.1, 0.0);
        var laserDir:b2Vec2 = new b2Vec2(segmentLength,0.0);
        segment.p1 = laserBody.GetWorldPoint(laserStart);
        segment.p2 = laserBody.GetWorldVector(laserDir);
        segment.p2+=segment.p1;
 
        var laserColor:b2Color = new b2Color(1,0,0);
        dbgDraw.DrawSegment(segment.p1, segment.p2, laserColor);
    }
 
 //I have a problem with this
 /*public static function Create() 
    {
        CutterTest();
    }*/
 
 
 /***************************************************/
 /*********************ETAPE 3***********************/
 /***************************************************/
 
  public var m_world:b2World;
  public var m_physScale:Number = 30;
  public var m_iterations:int = 10;
  public var m_timeStep:Number = 1/30;
 
  //Problème à  régler
  public const b2_maxPolygonVertices:int = 8;  
 
  //Programme
  public var poly:b2PolygonDef = new b2PolygonDef();
  public var newPolygon:b2PolygonDef = new b2PolygonDef();
  public const segment:b2Segment = new b2Segment();//???
  public var shape:b2PolygonShape;
  public var laserBody:b2Body;
 
  public var dbgDraw:b2DebugDraw;
 
  //Basics
  public var e_hitCollide = 1;
 
  public function update(e:Event):void{
   m_world.Step(m_timeStep, m_iterations);
  }
 }
}

1 2  下一页

Tags:The engine behind

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接