Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Tiny Wings game, Actionscript 3, Box2D, Flash and Game development.

When I introduced the scrolling in my Tiny Wings-like terrain I told you it would have been interesting to add a car to the game.

That’s what I made in this prototype:

You can control the cart with ARROW keys this way: UP: accelerate; DOWN: brake; LEFT: balance the cart on the left side; RIGHT: balance the cart on the right side.

And there’s not that much to say, apart from the cart creation which will be covered in a standalone post, I just scroll the game field and create new hills according to cart position rather than automatically like I did in the previous example.

And this is the commented source code:

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	import Box2D.Dynamics.Joints.*;
	public class Main extends Sprite {
		private var world:b2World=new b2World(new b2Vec2(0,10),true);
		private var worldScale:int=30;
		// variables which will be used to determine key pressed
		private var left:Boolean=false;
		private var right:Boolean=false;
		private var up:Boolean=false;
		private var down:Boolean=false;
		// the body of the cart
		private var cart:b2Body;
		// wheels motor speed
		private var motorSpeed:Number=0;
		// front and rear wheels revolute joints
		private var rearWheelRevoluteJoint:b2RevoluteJoint;
		private var frontWheelRevoluteJoint:b2RevoluteJoint;
		// random hill's height
		private var nextHill:Number=140+Math.random()*200;
		// build another hill when stage's x position is lower than this value
		private var buildNextHillAt:Number=0;
		public function Main():void {
			debugDraw();
			// we start with two hills
			nextHill=drawHill(10,0,nextHill);
			nextHill=drawHill(10,640,nextHill);
			addEventListener(Event.ENTER_FRAME,updateWorld);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,keyPressed);
			stage.addEventListener(KeyboardEvent.KEY_UP,keyReleased);
			// add the cart
			var carBodyDef:b2BodyDef = new b2BodyDef();
			carBodyDef.type=b2Body.b2_dynamicBody;
			carBodyDef.position.Set(320/worldScale,50/worldScale);
			carBodyDef.userData=new Object();
			var box:b2PolygonShape = new b2PolygonShape();
			box.SetAsBox(30/worldScale,10/worldScale);
			var boxDef:b2FixtureDef = new b2FixtureDef();
			boxDef.density=0.5;
			boxDef.friction=3;
			boxDef.restitution=0.3;
			boxDef.filter.groupIndex=-1;
			boxDef.shape=box;
			cart=world.CreateBody(carBodyDef);
			cart.CreateFixture(boxDef);
			// wheel shape
			var wheelShape:b2CircleShape=new b2CircleShape(12/worldScale);
			// wheel fixture
			var wheelFixture:b2FixtureDef = new b2FixtureDef();
			wheelFixture.density=1;
			wheelFixture.friction=3;
			wheelFixture.restitution=0.1;
			wheelFixture.filter.groupIndex=-1;
			wheelFixture.shape=wheelShape;
			// wheel body definition
			var wheelBodyDef:b2BodyDef = new b2BodyDef();
			wheelBodyDef.type=b2Body.b2_dynamicBody;
			// real wheel
			wheelBodyDef.position.Set(cart.GetWorldCenter().x-(16/worldScale),cart.GetWorldCenter().y+(15/worldScale));
			var rearWheel:b2Body=world.CreateBody(wheelBodyDef);
			rearWheel.CreateFixture(wheelFixture);
			// front wheel
			wheelBodyDef.position.Set(cart.GetWorldCenter().x+(16/worldScale),cart.GetWorldCenter().y+(15/worldScale));
			var frontWheel:b2Body=world.CreateBody(wheelBodyDef);
			frontWheel.CreateFixture(wheelFixture);
			// rear joint
			var rearWheelRevoluteJointDef:b2RevoluteJointDef=new b2RevoluteJointDef();
			rearWheelRevoluteJointDef.Initialize(rearWheel,cart,rearWheel.GetWorldCenter());
			rearWheelRevoluteJointDef.enableMotor=true;
			rearWheelRevoluteJointDef.maxMotorTorque=10000;
			rearWheelRevoluteJoint=world.CreateJoint(rearWheelRevoluteJointDef) as b2RevoluteJoint;
			// front joint
			var frontWheelRevoluteJointDef:b2RevoluteJointDef=new b2RevoluteJointDef();
			frontWheelRevoluteJointDef.Initialize(frontWheel,cart,frontWheel.GetWorldCenter());
			frontWheelRevoluteJointDef.enableMotor=true;
			frontWheelRevoluteJointDef.maxMotorTorque=10000;
			frontWheelRevoluteJoint=world.CreateJoint(frontWheelRevoluteJointDef) as b2RevoluteJoint;
		}
		private function drawHill(pixelStep:int,xOffset:Number,yOffset:Number):Number {
			var hillStartY:Number=yOffset;
			var hillWidth:Number=640;
			var hillSliceWidth=hillWidth/pixelStep;
			var hillVector:Vector.;
			var randomHeight:Number=Math.random()*100;
			if (xOffset!=0) {
				hillStartY-=randomHeight;
			}
			for (var j:int=0; j();
				hillVector.push(new b2Vec2((j*pixelStep+xOffset)/worldScale,480/worldScale));
				hillVector.push(new b2Vec2((j*pixelStep+xOffset)/worldScale,(hillStartY+randomHeight*Math.cos(2*Math.PI/hillSliceWidth*j))/worldScale));
				hillVector.push(new b2Vec2(((j+1)*pixelStep+xOffset)/worldScale,(hillStartY+randomHeight*Math.cos(2*Math.PI/hillSliceWidth*(j+1)))/worldScale));
				hillVector.push(new b2Vec2(((j+1)*pixelStep+xOffset)/worldScale,480/worldScale));
				var sliceBody:b2BodyDef=new b2BodyDef  ;
				var centre:b2Vec2=findCentroid(hillVector,hillVector.length);
				sliceBody.position.Set(centre.x,centre.y);
				for (var z:int=0; z, 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+1100) {
				motorSpeed=100;
			}
			// setting wheels motor speed
			rearWheelRevoluteJoint.SetMotorSpeed(motorSpeed);
			frontWheelRevoluteJoint.SetMotorSpeed(motorSpeed);
			world.Step(1/30,10,10);
			world.ClearForces();
			for (var currentBody:b2Body=world.GetBodyList(); currentBody; currentBody=currentBody.GetNext()) {
				// getting cart x position
				if (currentBody.GetUserData()!=null) {
					// adjusting stage position to keep cart in the vertical middle of the stage
					x=320-currentBody.GetPosition().x*worldScale;
					// checking if it's time to add a new hill
					if (x<=buildNextHillAt) {
						buildNextHillAt-=640;
						nextHill=drawHill(10,- buildNextHillAt+640,nextHill);
					}
				}
				if (currentBody.GetPosition().x*worldScale<(x*-1)-640) {
					world.DestroyBody(currentBody);
				}
			}
			world.DrawDebugData();
		}
	}
}

No need to download anything, just copy and paste it on the class you can find in the first post.

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