Previous posts focused on Sokoban game like simple Prototype and then prototype with textures was prepared without refreshing any documentation for A3d.

Well I checked A3d examples and found that there is SkyBox feature. And it is really easy to add animated characters to scene, and then choose prepared animation. And it is better to fix axes before use and etc… Good experience for future to read manuals before coding.
Black voodoo manipulations with camera angles now removed, because all axes became native for A3d engine.

Now camera have free mode too, use F button to activate that mode, then use W,A,S,D and mouse to control camera.

Other controls are the same, keyboard arrows Up, Left, Right.

Here you can check latest sokoban version with animated guy:

This movie requires Flash Player 9


Here is source code:

package 
{
	import alternativa.Alternativa3D;
	import alternativa.engine3d.animation.AnimationClip;
	import alternativa.engine3d.animation.AnimationController;
	import alternativa.engine3d.animation.AnimationSwitcher;
	import alternativa.engine3d.containers.*;
	import alternativa.engine3d.controllers.*;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Clipping;
	import alternativa.engine3d.core.Debug;
	import alternativa.engine3d.core.MipMapping;
	import alternativa.engine3d.core.MouseEvent3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Object3DContainer;
	import alternativa.engine3d.core.Sorting;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.loaders.ParserCollada;
	import alternativa.engine3d.materials.FillMaterial;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.objects.Skin;
	import alternativa.engine3d.objects.SkyBox;
	import alternativa.engine3d.objects.Sprite3D;
	import alternativa.engine3d.primitives.Box;
	import alternativa.engine3d.primitives.Plane;
	import alternativa.engine3d.primitives.Sphere;
	
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.filters.GlowFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Vector3D;
	import flash.sampler.NewObjectSample;
	import flash.system.Capabilities;
	import flash.ui.Keyboard;
	
	[SWF(backgroundColor="#000000", frameRate="100", width="640", height="480")]
	public class alternativa3dSokoban extends Sprite 
	{
		private const CUBESIZE:Number=120;
		//embeding textures images
		[Embed(source="resource/crateTextureImg.jpg")] static private const crateTextureImg:Class;
		[Embed(source="resource/floorTextureImg.png")] static private const floorTextureImg:Class;
		[Embed(source="resource/crateTopTextureImg.jpg")] static private const crateTopTextureImg:Class;
		[Embed(source="resource/crateTopGoalTextureImg.jpg")] static private const crateTopGoalTextureImg:Class;
		[Embed(source="resource/wallTextureImg.png")] static private const wallTextureImg:Class;
		[Embed(source="resource/goalTextureImg.jpg")] static private const goalTextureImg:Class;
		[Embed(source="resource/playerTextureImg.jpg")] static private const playerTextureImg:Class;
		[Embed(source="resource/backBitmapImg.jpg")] static private const backTextureImg:Class;
		[Embed(source="resource/backBottomBitmapImg.jpg")] static private const backBottomTextureImg:Class;
		
		//3d man
		[Embed("resource/character.DAE", mimeType="application/octet-stream")] static private const CharacterModel:Class;
		[Embed(source="resource/character.jpg")] static private const CharacterTexture:Class;
		
		private var character:Skin;
		private var animationController:AnimationController = new AnimationController();
		private var animationSwitcher:AnimationSwitcher = new AnimationSwitcher();
		private var idle:AnimationClip;
		private var run:AnimationClip;
		private var lastTime:int = 0;
		private var timeScale:Number = 0.8;
		
		// 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;
		
		// alternativa3d  engine variables
		private var camera:Camera3D;
		private var controller:SimpleObjectController;
		private var container:ConflictContainer;			
		private var frame:Sprite = new Sprite();
		public var player:Sphere;// Sphere primitive representing the player
		public var cplayer:SimpleObjectController; //controller for player object
		public var conplayer:Object3DContainer; //container for player
		private var movingCrate:Box;// cube primitive representing the moving crate		
		private var fixedcamera:Boolean = true;
		
		// textures		
		private var crateTexture:TextureMaterial = new TextureMaterial(new crateTextureImg().bitmapData);
		private var floorTexture:TextureMaterial = new TextureMaterial(new floorTextureImg().bitmapData);
		private var crateTopTexture:TextureMaterial = new TextureMaterial(new crateTopTextureImg().bitmapData);
		private var crateTopGoalTexture:TextureMaterial = new TextureMaterial(new crateTopGoalTextureImg().bitmapData);
		private var wallTexture:TextureMaterial = new TextureMaterial(new wallTextureImg().bitmapData);
		private var goalTexture:TextureMaterial = new TextureMaterial(new goalTextureImg().bitmapData);
		private var playerTexture:TextureMaterial = new TextureMaterial(new playerTextureImg().bitmapData);
		// SkyBox textures
		private var skybox:SkyBox;
		private var backTexture:TextureMaterial = new TextureMaterial(new backTextureImg().bitmapData);
		private var backBottomTexture:TextureMaterial = new TextureMaterial(new backBottomTextureImg().bitmapData);
		
		public function alternativa3dSokoban() 
		{			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.quality = StageQuality.BEST;
			
			// Camera
			camera = new Camera3D();
			camera.view = new View(640, 480);
			
			addChild(camera.view);
			
			// Camera controller
			controller = new SimpleObjectController(stage, camera, 200, 3);
			//unbing caracter controll keys
			controller.unbindKey(Keyboard.UP);
			controller.unbindKey(Keyboard.LEFT);
			controller.unbindKey(Keyboard.RIGHT);
			controller.unbindKey(Keyboard.DOWN);
			
			// Root object
			container = new ConflictContainer();
			container.resolveByAABB = true;
			container.resolveByOOBB = true;
			
			//Player controller
			conplayer = new Object3DContainer();
			cplayer = new SimpleObjectController(stage, player, 3);
			
			//i am not shure about SkyBox in Alternativa and will prepare it manually
			//fixed. There is default SkyBox
			skybox = new SkyBox(200*CUBESIZE/2,backTexture,backTexture,backTexture,backTexture,backBottomTexture,backBottomTexture);
			container.addChild(skybox);
			// end SkyBox
			
			var box:Box;
			/*
			[[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]];
			*/
			// level construction
			for (var i:uint=0; i<6; i++) 
			{
				for (var j:uint=0; j<8; j++) 
				{
					switch (levels[i][j]) 
					{
						case 0 :
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE/2,1,1);
							box.setMaterialToAllFaces(floorTexture);
							box.x = CUBESIZE*j;
							box.z = 0;
							box.y = CUBESIZE*i;

							container.addChild(box);
							break;
						case 1 :
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE/2,1);
							box.setMaterialToAllFaces(floorTexture);
							box.x = CUBESIZE*j;
							box.z = 0;
							box.y = CUBESIZE*i;
							container.addChild(box);
							
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE,1);
							box.setMaterialToAllFaces(wallTexture);
							box.x = CUBESIZE*j;
							box.z = CUBESIZE*3/4;
							box.y = CUBESIZE*i;
							container.addChild(box);
							break;
						case 2 :
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE/2,1);
							box.setMaterialToAllFaces(goalTexture);
							box.x = CUBESIZE*j;
							box.z = 0;
							box.y = CUBESIZE*i;
							container.addChild(box);
							break;
						case 3 :
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE/2,1);
							box.setMaterialToAllFaces(floorTexture);
							box.x = CUBESIZE*j;
							box.z = 0;
							box.y = CUBESIZE*i;
							container.addChild(box);
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE,1);
							box.name = "crate_"+i+"_"+j;
							box.setMaterialToAllFaces(crateTexture);
							box.x = CUBESIZE*j;
							box.z = CUBESIZE*3/4;
							box.y = CUBESIZE*i;
							
							// top of the crate
							box.faces[4].material=crateTopTexture;
							box.faces[5].material=crateTopTexture;
							
							container.addChild(box);
							break;
						case 4 :
							box = new Box(CUBESIZE,CUBESIZE,CUBESIZE/2,1);
							box.setMaterialToAllFaces(floorTexture);
							box.x = CUBESIZE*j;
							box.z = 0;
							box.y = CUBESIZE*i;
							container.addChild(box);
							
							player = new Sphere(CUBESIZE/2,16,16,false,playerTexture);
							
							// Parser of character
							var characterParser:ParserCollada = new ParserCollada();
							characterParser.parse(XML(new CharacterModel()));
							character = characterParser.getObjectByName("character") as Skin;
							var characterMaterial:TextureMaterial = new TextureMaterial(new CharacterTexture().bitmapData);
							character.setMaterialToAllFaces(characterMaterial);
							
							character.rotationZ += 270*Math.PI/180;
							
							//to do check object posistion in 3dMax.
							//remove levitation
							character.z -= 55;

							conplayer.addChild(player);
							player.visible = false;
							conplayer.visible = true;
							conplayer.x = CUBESIZE*j;
							conplayer.z = CUBESIZE*3/4;
							conplayer.y = CUBESIZE*i;

							container.addChild(conplayer);
							conplayer.addChild(character);
							playerCol=j;
							playerRow=i;
							
							// Character animation
							var animation:AnimationClip = characterParser.getAnimationByObject(character);
							
							// Slice of animation
							idle = animation.slice(0, 40/30);
							run = animation.slice(41/30, 61/30);
							
							// Adding 
							animationSwitcher.addAnimation(idle);
							animationSwitcher.addAnimation(run);
							
							// Running
							animationSwitcher.activate(idle, 0.1);
							animationSwitcher.speed = timeScale;
							
							animationController.root = animationSwitcher;
							animationSwitcher.activate(idle, 0.1);
							
							break;
					}
				}
			}
			
			// Adding camera
			container.addChild(camera);
			
			// View frame
			addChild(frame);												
			onResize();		
			stage.addEventListener(Event.ENTER_FRAME, updateEvent);			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDwn);		
			stage.addEventListener(Event.RESIZE, onResize);
		}
		
		private function onKeyDwn(e:KeyboardEvent):void 
		{
			if (playerRotation==0&&playerMovement==0) 
			{
				switch (e.keyCode) 
				{
					case 70 :
						if (fixedcamera)
						{
							fixedcamera = false;							
						}
						else
						{
							fixedcamera = true;
						}						 
						break;
					case Keyboard.LEFT :
						playerRotation=+9;
						playerAngle+=90;
						animationSwitcher.activate(run, 0.1);
						break;
					case Keyboard.RIGHT :
						playerRotation=-9;
						playerAngle-=90;
						animationSwitcher.activate(run, 0.1);
						break;
					case Keyboard.UP :
						animationSwitcher.activate(run, 0.1);
						movingCrate=null;
						playerAngle=Math.round(conplayer.rotationZ*180/Math.PI)%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=container.getChildByName("crate_"+(playerRow+dRow)+"_"+(playerCol+dCol))as Box;
									playerMovement=-CUBESIZE/10;
								}
							}
						}
						break;
					
				}
			}
		}
		
		
		public function updateEvent(e:Event):void 
		{		
			if (playerRotation) 
			{
				conplayer.rotationZ+=playerRotation*Math.PI/180;
				
				if (Math.abs(Math.round(conplayer.rotationZ*180/Math.PI))%90==0)
				{
					playerRotation=0;
					animationSwitcher.activate(idle, 0.1);
				}
			}
			
			if (playerMovement) 
			{					
				switch (playerAngle) 
				{
					case 0 :
						conplayer.x += playerMovement;
						break;
					case 90 :
						conplayer.y += playerMovement;
						break;
					case 180 :
						conplayer.x += -playerMovement;
						break;
					case 270 :
						conplayer.y += -playerMovement;
						break;
				}
				
				if (movingCrate) 
				{
					switch (playerAngle) 
					{
						case 0 :
							movingCrate.x += playerMovement;
							break;
						case 90 :
							movingCrate.z += -playerMovement;
							break;
						case 180 :
							movingCrate.x += -playerMovement;
							break;
						case 270 :
							movingCrate.z += playerMovement;
							break;
					}
				}
				
				// we need this to know if the player stopped on the destination tile
				if ((playerAngle%180==0&&(Math.round(conplayer.x*10)/10)%CUBESIZE==0)||(playerAngle%180!=0&&(Math.round(conplayer.y*10)/10)%CUBESIZE==0)) 
				{
					animationSwitcher.activate(idle, 0.1);
					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) {
							// changing materials on the fly
							movingCrate.setMaterialToAllFaces(crateTexture);
							// top of the crate on goal
							movingCrate.faces[4].material=crateTopGoalTexture;
							movingCrate.faces[5].material=crateTopGoalTexture;								
							
						}
						else 
						{
							//movingCrate.setMaterialToAllFaces(crateMaterial);
							movingCrate.setMaterialToAllFaces(crateTexture);
							// top of the crate
							movingCrate.faces[4].material=crateTopTexture;
							movingCrate.faces[5].material=crateTopTexture;								
						}
						levels[playerRow+dRow][playerCol+dCol]-=3;
						movingCrate.name="crate_"+(playerRow+2*dRow)+"_"+(playerCol+2*dCol);
					}
					playerCol+=dCol;
					playerRow+=dRow;
				}
			}
			
			onEnterFrame();
		}			
		
		public function correct_camera_angles():void
		{
			//set camera position
			var r:Number = 10*CUBESIZE/3;			
			var a:Number = conplayer.rotationZ;
			var cx:Number = conplayer.x+Math.cos(a)*r;
			var cy:Number = conplayer.y+Math.sin(a)*r;
			var cz:Number = conplayer.z+r;			
			controller.setObjectPosXYZ(cx,cy,cz);			
			//look at player box
			controller.lookAtXYZ(conplayer.x,conplayer.y,conplayer.z);

		}
		
		public function onEnterFrame(e:Event = null):void 
		{
			controller.update();
			animationController.update();
			if (fixedcamera)
			{
				correct_camera_angles();
			}
			cplayer.update();
			camera.render();		
		}
		
		
		public function onResize(e:Event = null):void 
		{
			//here you can add border size for view
			var pd:Number = 0;
			camera.view.width = stage.stageWidth - pd*2;
			camera.view.height = stage.stageHeight - pd*2;
			camera.view.x = pd;
			camera.view.y = pd;
			
			frame.graphics.clear();
			frame.graphics.beginFill(0x000000, 0);
			frame.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			frame.graphics.drawRect(pd, pd, camera.view.width, camera.view.height);
			frame.graphics.endFill();
		}
	}
}

Here you can download sources.

5 responses


Do you want to comment?

Comments RSS and TrackBack Identifier URI ?

Love U! Great Job!

February 28, 2011 7:36 pm

Thanks!

February 28, 2011 8:56 pm

Excellent! … many thanks for sharing this information, please add more :-)

May 23, 2011 12:35 pm

excellent brilliant work.

June 6, 2012 4:12 pm

Nice!

July 1, 2012 5:42 am

Comment now!
















Trackbacks