Get the full commented source code of

HTML5 Suika Watermelon Game

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

This post should end the Sokoban game prototype made with Flare3D started here and continued here.

The changes in this version are:

* Added some textures
* Fixed multiple keys pressed bug
* Changed player to a rolling sphere
* Added background environment

This is the source code:

package {
	// required flash classes
	import flash.geom.Vector3D;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.filters.*;
	// required flare3d classes
	import flare.basic.*;
	import flare.materials.*;
	import flare.primitives.*;
	import flare.system.*;
	import flare.utils.*;
	import flare.core.*;
	public class Main extends Sprite {
		private const CUBESIZE:Number=10;
		// 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;
		// flare3d variables
		private var scene:Scene3D;// scene3D is the canvas of the flare3d environment
		private var player:Sphere;// sphere primitive representing the player
		private var cameraTarget:Sphere;// sphere to be used as camera target
		private var movingCrate:Cube;// cube primitive representing the moving crate
		// bitmap datas
		private var crateBitmap:BitmapData=new BitmapData(256,256);
		private var crateTopBitmap:BitmapData=new BitmapData(256,256);
		private var crateTopGoalBitmap: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 playerBitmap:BitmapData=new BitmapData(512,512);
		private var backBitmap:BitmapData=new BitmapData(512,512);
		private var backBottomBitmap:BitmapData=new BitmapData(512,512);
		// textures
		private var crateTexture:Texture3D;
		private var crateTopTexture:Texture3D;
		private var crateTopGoalTexture:Texture3D;
		private var floorTexture:Texture3D=new Texture3D("",floorBitmap);
		private var backTexture:Texture3D=new Texture3D("",backBitmap);
		private var wallTexture:Texture3D;
		private var playerTexture:Texture3D;
		private var goalTexture:Texture3D=new Texture3D("",goalBitmap);
		// materials
		private var floorMaterial:TextureMaterial=new TextureMaterial("",floorTexture);
		private var goalMaterial:TextureMaterial=new TextureMaterial("",goalTexture);
		// multi materials
		private var wallMaterial:MultiMaterial = new MultiMaterial();
		private var crateMaterial:MultiMaterial = new MultiMaterial();
		private var crateTopMaterial:MultiMaterial = new MultiMaterial();
		private var crateTopGoalMaterial:MultiMaterial = new MultiMaterial();
		private var playerMaterial:MultiMaterial = new MultiMaterial();
		public function Main() {
			floorBitmap.draw(new floorPic(256,256));
			goalBitmap.draw(new goalPic(256,256));
			backBitmap.draw(new backPic(512,512));
			backBottomBitmap.draw(new backBottomPic(512,512));
			//
			wallBitmap.draw(new wallPic(256,256));
			wallTexture=new Texture3D("",wallBitmap);
			wallMaterial.setTextureChannel(0,wallTexture);
			wallMaterial.setShadedColorChannel(1);
			wallMaterial.setBlendMode(BlendMode.MULTIPLY);
			//
			crateBitmap.draw(new cratePic(256,256));
			crateTexture=new Texture3D("",crateBitmap);
			crateMaterial.setTextureChannel(0,crateTexture);
			crateMaterial.setShadedColorChannel(1);
			crateMaterial.setBlendMode(BlendMode.MULTIPLY);
			//
			crateTopBitmap.draw(new crateTopPic(256,256));
			crateTopTexture=new Texture3D("",crateTopBitmap);
			crateTopMaterial.setTextureChannel(0,crateTopTexture);
			crateTopMaterial.setShadedColorChannel(1);
			crateTopMaterial.setBlendMode(BlendMode.MULTIPLY);
			//
			crateTopGoalBitmap.draw(new crateTopGoalPic(256,256));
			crateTopGoalTexture=new Texture3D("",crateTopGoalBitmap);
			crateTopGoalMaterial.setTextureChannel(0,crateTopGoalTexture);
			crateTopGoalMaterial.setShadedColorChannel(1);
			crateTopGoalMaterial.setBlendMode(BlendMode.MULTIPLY);
			//
			playerBitmap.draw(new playerPic(512,512));
			playerTexture=new Texture3D("",playerBitmap);
			playerMaterial.setTextureChannel(0,playerTexture);
			playerMaterial.setShadedColorChannel(1);
			playerMaterial.setBlendMode(BlendMode.MULTIPLY);
			// scene setup
			scene=new Viewer3D(this,"",0,0);
			// background evironment
			var front:Texture3D=new Texture3D("",backBitmap);
			front.filename="front.png";
			var back:Texture3D=new Texture3D("",backBitmap);
			back.filename="back.png";
			var left:Texture3D=new Texture3D("",backBitmap);
			left.filename="left.png";
			var right:Texture3D=new Texture3D("",backBitmap);
			right.filename="right.png";
			var top:Texture3D=new Texture3D("",backBitmap);
			top.filename="top.png";
			var bottom:Texture3D=new Texture3D("",backBottomBitmap);
			bottom.filename="bottom.png";
			Resources3D.addTexture(front);
			Resources3D.addTexture(back);
			Resources3D.addTexture(left);
			Resources3D.addTexture(right);
			Resources3D.addTexture(top);
			Resources3D.addTexture(bottom);
			var sky:SkyBox=new SkyBox("","","png",50);
			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("",CUBESIZE,CUBESIZE/2,CUBESIZE,1,floorMaterial);
							cube.setPosition(CUBESIZE*j,0,CUBESIZE*i);
							scene.addChild(cube);
							break;
						case 1 :
							cube=new Cube("",CUBESIZE,CUBESIZE/2,CUBESIZE,1,floorMaterial);
							cube.setPosition(CUBESIZE*j,0,CUBESIZE*i);
							scene.addChild(cube);
							cube=new Cube("",CUBESIZE,CUBESIZE,CUBESIZE,1,wallMaterial);
							cube.setPosition(CUBESIZE*j,CUBESIZE*3/4,CUBESIZE*i);
							scene.addChild(cube);
							break;
						case 2 :
							cube=new Cube("",CUBESIZE,CUBESIZE/2,CUBESIZE,1,goalMaterial);
							cube.setPosition(CUBESIZE*j,0,CUBESIZE*i);
							scene.addChild(cube);
							break;
						case 3 :
							cube=new Cube("",CUBESIZE,CUBESIZE/2,CUBESIZE,1,floorMaterial);
							cube.setPosition(CUBESIZE*j,0,CUBESIZE*i);
							scene.addChild(cube);
							cube=new Cube("crate_"+i+"_"+j,CUBESIZE,CUBESIZE,CUBESIZE,1,crateMaterial);
							cube.setPosition(CUBESIZE*j,CUBESIZE*3/4,CUBESIZE*i);
							scene.addChild(cube);
							// top of the crate
							var polyVec:Vector.=cube.polys;
							polyVec[4].material=crateTopMaterial;
							polyVec[5].material=crateTopMaterial;
							break;
						case 4 :
							cube=new Cube("",CUBESIZE,CUBESIZE/2,CUBESIZE,1,floorMaterial);
							cube.setPosition(CUBESIZE*j,0,CUBESIZE*i);
							scene.addChild(cube);
							player=new Sphere("player",CUBESIZE/2,24,playerMaterial);
							player.setPosition(CUBESIZE*j,CUBESIZE*3/4,CUBESIZE*i);
							scene.addChild(player);
							cameraTarget=new Sphere("cameraTarget",1,12,crateTopMaterial);
							cameraTarget.setPosition(CUBESIZE*j,CUBESIZE*3/4,CUBESIZE*i);
							scene.addChild(cameraTarget);
							playerCol=j;
							playerRow=i;
							break;
					}
				}
			}
			// listener to handle the 3D engine
			scene.addEventListener(Scene3D.UPDATE_EVENT,updateEvent);
		}
		private function updateEvent(e:Event):void {
			var currentRotation:Number=0;
			// 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 (playerRotation==0&&playerMovement==0) {
				// look how does flare3D listens for key pressed
				if (Input3D.keyDown(Input3D.RIGHT)) {
					playerRotation=9;
					playerAngle+=90;
				} else {
					if (Input3D.keyDown(Input3D.LEFT)) {
						playerRotation=-9;
						playerAngle-=90;
					} else {
						if (Input3D.keyDown(Input3D.UP)) {
							movingCrate=null;
							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=scene.getChildByName("crate_"+(playerRow+dRow)+"_"+(playerCol+dCol))as Cube;
										playerMovement=- CUBESIZE/10;
									}
								}
							}
						}
					}
				}
				if (playerAngle<0) {
					playerAngle+=360;
				}
				if (playerAngle==360) {
					playerAngle=0;
				}
			} else {
				if (playerRotation) {
					cameraTarget.rotateY(playerRotation);
					if (Math.abs(Math.round(cameraTarget.getRotation().y))%90==0) {
						playerRotation=0;
					}
				}
				if (playerMovement) {
					var vectorAngle:Vector3D=player.getRotation();
					cameraTarget.translateX(playerMovement);
					switch (playerAngle) {
						case 0 :
							player.x+=playerMovement;
							if (Math.abs(Math.round(vectorAngle.x))==180) {
								player.rotateZ(-18);
							} else {
								player.rotateZ(18);
							}
							if (movingCrate) {
								movingCrate.translateX(playerMovement);
							}
							break;
						case 90 :
							player.z-=playerMovement;
							if (Math.abs(Math.round(vectorAngle.z))==180) {
								player.rotateX(-18);
							} else {
								player.rotateX(18);
							}
							if (movingCrate) {
								movingCrate.translateZ(-playerMovement);
							}
							break;
						case 180 :
							player.x-=playerMovement;
							if (Math.abs(Math.round(vectorAngle.x))==180) {
								player.rotateZ(18);
							} else {
								player.rotateZ(-18);
							}
							if (movingCrate) {
								movingCrate.translateX(-playerMovement);
							}
							break;
						case 270 :
							player.z+=playerMovement;
							if (Math.abs(Math.round(vectorAngle.z))==180) {
								player.rotateX(18);
							} else {
								player.rotateX(-18);
							}
							if (movingCrate) {
								movingCrate.translateZ(playerMovement);
							}
							break;
					}
					// we need this to know if the player stopped on the destination tile
					if ((playerAngle%180==0&&(Math.round(player.getPosition().x*10)/10)%CUBESIZE==0)||(playerAngle%180!=0&&(Math.round(player.getPosition().z*10)/10)%CUBESIZE==0)) {
						playerMovement=0;
						levels[playerRow+dRow][playerCol+dCol]+=4;
						levels[playerRow][playerCol]-=4;
						if (movingCrate) {
							var polyVec:Vector.=movingCrate.polys;
							levels[playerRow+2*dRow][playerCol+2*dCol]+=3;
							if (levels[playerRow+2*dRow][playerCol+2*dCol]==5) {
								polyVec[4].material=crateTopGoalMaterial;
								polyVec[5].material=crateTopGoalMaterial;
							} else {
								polyVec[4].material=crateTopMaterial;
								polyVec[5].material=crateTopMaterial;
							}
							levels[playerRow+dRow][playerCol+dCol]-=3;
							movingCrate.name="crate_"+(playerRow+2*dRow)+"_"+(playerCol+2*dCol);
						}
						playerCol+=dCol;
						playerRow+=dRow;
					}
				}
			}
			// camera management
			Pivot3DUtils.setPositionWithReference(scene.camera,CUBESIZE*3,CUBESIZE*6,0,cameraTarget,0.1);
			Pivot3DUtils.lookAtWithReference(scene.camera,-CUBESIZE*2,0,0,cameraTarget);
		}
	}
}

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.