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:
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 ?
Trackbacks