Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Splitter game, Actionscript 3, Box2D, Flash and Users contributions.

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 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  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 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 = 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 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] 

And this is the source with raycast for Box2D included.

The scripts gave no errors so I think we are close to the solution, I will take a look at it during the next days, meanwhile if you find out what's wrong, you know where to comment :)

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