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 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);
}
}
}
- ››TheServerSide网站2009年最热文章
- ››The Netron Project For vb.net
- ››The engine behind Splitter Flash game : workin...
- ››The engine behind Splitter Flash game – first...
- ››The engine behind Splitter Flash game – new A...
- ››The Standard C Library for Linux
- ››The File System(文件系统)
- ››The Standard C Library for Linux:ctype.h
- ››The Standard C Library for Linux:stdlib.h
- ››The Model-View-Controller Architecture
- ››The Three Faces of SOA
- ››The Alloy Look And Feel 1.4.4破解手记
赞助商链接