Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Sokoban game, 3D, Actionscript 3, Flash and Game development.

This is the Away3D script which includes the same features I showed you in the Flare3D version.

There are a couple of issues, like lines 246 and 248 which do not correctly change the crate top material once it’s over a goal, and a really low framerate if I enable the Z ordering at line 62.

Anyway, this is the script:

package {
	// required flash classes
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Vector3D;
	import flash.display.BitmapData;
	// required awayed classes
	import away3d.containers.*;
	import away3d.primitives.*;
	import away3d.cameras.*;
	import away3d.core.render.*;
	import away3d.materials.*;
	import away3d.lights.DirectionalLight3D;
	import away3d.debug.*;
	public class Main extends Sprite {
		private const CUBESIZE:Number=50;
		// sokobal demo level and player position
		private var levels:Array=[[1,1,1,1,0,0,0,0],[1,0,0,1,1,1,1,1],[1,0,2,0,0,3,0,1],[1,0,3,0,0,2,4,1],[1,1,1,0,0,1,1,1],[0,0,1,1,1,1,0,0]];
		private var playerCol:uint;
		private var playerRow:uint;
		private var playerRotation:Number=0;
		private var playerAngle:Number=0;
		private var playerMovement:Number=0;
		private var dRow:int;
		private var dCol:int;
		// away3d variables
		private var view:View3D;// View3D represent the canvas
		private var theCamera:SpringCam;// custom camera to manage 1st or 3rd person camera
		private var player:Sphere;// the player
		private var cameraTarget:Sphere;
		private var movingCrate:Cube;// the crate which will be pushed
		// bitmap datas
		private var crateBitmap:BitmapData=new BitmapData(256,256);
		private var crateTopBitmap:BitmapData=new BitmapData(256,256);
		private var floorBitmap:BitmapData=new BitmapData(256,256);
		private var wallBitmap:BitmapData=new BitmapData(256,256);
		private var goalBitmap:BitmapData=new BitmapData(256,256);
		private var crateTopGoalBitmap:BitmapData=new BitmapData(256,256);
		private var backBitmap:BitmapData=new BitmapData(512,512);
		private var playerBitmap:BitmapData=new BitmapData(512,512);
		// some materials
		private var floorMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(floorBitmap);
		private var wallMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(wallBitmap);
		private var goalMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(goalBitmap);
		private var crateMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(crateBitmap);
		private var crateTopMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(crateTopBitmap);
		private var crateTopGoalMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(crateTopGoalBitmap);
		private var backMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(backBitmap);
		private var playerMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(playerBitmap);
		function Main() {
			floorBitmap.draw(new floorPic(256,256));
			wallBitmap.draw(new wallPic(256,256));
			crateBitmap.draw(new cratePic(256,256));
			crateTopBitmap.draw(new crateTopPic(256,256));
			crateTopGoalBitmap.draw(new crateTopGoalPic(256,256));
			goalBitmap.draw(new goalPic(256,256));
			backBitmap.draw(new backPic(512,512));
			playerBitmap.draw(new playerPic(512,512));
			// scene setup
			view=new View3D({x:320,y:240});
			//view.renderer = Renderer.CORRECT_Z_ORDER;
			var stats:AwayStats=new AwayStats(view);
			addChild(view);
			addChild(stats);
			theCamera= new SpringCam();
			view.camera=theCamera;
			var light:DirectionalLight3D = new DirectionalLight3D();
			light.direction=new Vector3D(CUBESIZE*10,- CUBESIZE*6,CUBESIZE*4);
			view.scene.addLight(light);
			var sky:Skybox=new Skybox(backMaterial,backMaterial,backMaterial,backMaterial,backMaterial,backMaterial);
			view.scene.addChild(sky);
			// level construction
			var cube=Cube;
			for (var i:uint=0; i<6; i++) {
				for (var j:uint=0; j<8; j++) {
					switch (levels[i][j]) {
						case 0 :
							cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
							view.scene.addChild(cube);
							break;
						case 1 :
							cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
							view.scene.addChild(cube);
							cube=new Cube({material:wallMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
							view.scene.addChild(cube);
							break;
						case 2 :
							cube=new Cube({material:goalMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
							view.scene.addChild(cube);
							break;
						case 3 :
							cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
							view.scene.addChild(cube);
							cube=new Cube({material:crateMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
							cube.cubeMaterials.bottom=crateTopMaterial;
							cube.name="crate_"+i+"_"+j;
							view.scene.addChild(cube);
							break;
						case 4 :
							cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
							view.scene.addChild(cube);
							player=new Sphere({material:playerMaterial,radius:CUBESIZE/2,segmentsW:16,segmentsH:16,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
							view.scene.addChild(player);
							cameraTarget=new Sphere({material:playerMaterial,radius:CUBESIZE/5,segmentsW:4,segmentsH:4,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
							view.scene.addChild(cameraTarget);
							playerCol=j;
							playerRow=i;
							break;
					}
				}
			}
			// listeners
			addEventListener(Event.ENTER_FRAME,onEnterFrm);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDwn);
		}
		private function onKeyDwn(e:KeyboardEvent):void {
			if (playerRotation==0&&playerMovement==0) {
				switch (e.keyCode) {
					case 37 :
						playerRotation=-9;
						break;
					case 38 :
						movingCrate=null;
						var playerAngle:Number=Math.round(player.rotationY)%360;
						if (playerAngle<0) {
							playerAngle+=360;
						}
						// we have to determine the difference between current row and column
						// and the new row and column according to player heading
						switch (playerAngle) {
							case 0 :
								dRow=0;
								dCol=-1;
								break;
							case 90 :
								dRow=-1;
								dCol=0;
								break;
							case 180 :
								dRow=0;
								dCol=1;
								break;
							case 270 :
								dRow=1;
								dCol=0;
								break;
						}
						if (levels[playerRow+dRow][playerCol+dCol]==0||levels[playerRow+dRow][playerCol+dCol]==2) {
							// the player can move
							playerMovement=- CUBESIZE/10;
						} else {
							if (levels[playerRow+dRow][playerCol+dCol]==3||levels[playerRow+dRow][playerCol+dCol]==5) {
								if (levels[playerRow+2*dRow][playerCol+2*dCol]==0||levels[playerRow+2*dRow][playerCol+2*dCol]==2) {
									// the player can move and can push a crate
									movingCrate=view.scene.getChildByName("crate_"+(playerRow+dRow)+"_"+(playerCol+dCol))as Cube;
									playerMovement=- CUBESIZE/10;
								}
							}
						}
						break;
					case 39 :
						playerRotation=9;
						break;
				}
			}
		}
		private function onEnterFrm(e:Event):void {
			if (playerRotation) {
				// this is how away3d rotates an object
				player.rotationY+=playerRotation;
				cameraTarget.rotationY+=playerRotation;
				var reachedAngle:Number=Math.round(player.rotationY);
				if (reachedAngle%90==0) {
					playerRotation=0;
				}
			}
			if (playerMovement) {
				playerAngle=Math.round(player.rotationY)%360;
				if (playerAngle<0) {
					playerAngle+=360;
				}
				// this is how away3d moves an object
				cameraTarget.moveForward(playerMovement);
				switch (playerAngle) {
					case 0 :
						player.z+=playerMovement;
						if (Math.round(player.rotationZ)%360==0) {
							player.rotationX+=18;
						} else {
							player.rotationX-=18;
						}
						break;
					case 90 :
						player.x+=playerMovement;
						player.rotationZ+=18;
						break;
					case 180 :
						player.z-=playerMovement;
						if (Math.round(player.rotationZ)%360==0) {
							player.rotationX+=18;
						} else {
							player.rotationX-=18;
						}
						break;
					case 270 :
						player.x-=playerMovement;
						player.rotationZ-=18;
						break;
				}
				if (movingCrate) {
					if (playerAngle<0) {
						playerAngle+=360;
					}
					switch (playerAngle) {
						case 0 :
							movingCrate.moveForward(playerMovement);
							break;
						case 90 :
							movingCrate.moveRight(playerMovement);
							break;
						case 180 :
							movingCrate.moveBackward(playerMovement);
							break;
						case 270 :
							movingCrate.moveLeft(playerMovement);
							break;
					}
				}
				// we need this to know if the player stopped on the destination tile
				if (Math.round(player.rotationY)%180==0) {
					if (Math.round(player.z)%CUBESIZE==0) {
						playerMovement=0;
					}
				} else {
					if (Math.round(player.x)%CUBESIZE==0) {
						playerMovement=0;
					}
				}
				if (playerMovement==0) {
					levels[playerRow+dRow][playerCol+dCol]+=4;
					levels[playerRow][playerCol]-=4;
					if (movingCrate) {
						levels[playerRow+2*dRow][playerCol+2*dCol]+=3;
						if (levels[playerRow+2*dRow][playerCol+2*dCol]==5) {
							movingCrate.cubeMaterials.bottom=crateTopGoalMaterial;
						} else {
							movingCrate.cubeMaterials.bottom=crateTopMaterial;
						}
						levels[playerRow+dRow][playerCol+dCol]-=3;
						movingCrate.name="crate_"+(playerRow+2*dRow)+"_"+(playerCol+2*dCol);
						movingCrate=null;
					}
					playerRow+=dRow;
					playerCol+=dCol;
				}
			}
			// camera management
			theCamera.target=cameraTarget;
			theCamera.positionOffset=new Vector3D(0,CUBESIZE*8,CUBESIZE*6);
			theCamera.lookOffset=new Vector3D(0,0,-2*CUBESIZE);
			theCamera.damping=10;
			theCamera.view;
			view.render();

		}
	}
}

and this is the result:

Download the source code.

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