package
{
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.Sorting;
import alternativa.engine3d.core.View;
import alternativa.engine3d.materials.FillMaterial;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.objects.Sprite3D;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.primitives.Plane;
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
{
// 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:Box;// cube primitive representing the player
public var cplayer:SimpleObjectController;
private var movingCrate:Box;// cube primitive representing the moving crate
// some materials
private var wallMaterial:FillMaterial = new FillMaterial(0x880088,1,1);
private var crateMaterial:FillMaterial = new FillMaterial(0xff0000,1,1);
private var playerMaterial:FillMaterial = new FillMaterial(0x0000ff,1,1);
private var floorMaterial:FillMaterial = new FillMaterial(0x888888,1,1);
private var goalMaterial:FillMaterial = new FillMaterial(0x00ff00,1,1);
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(800, 600);
addChild(camera.view);
// Camera controller
controller = new SimpleObjectController(stage, camera, 200, 3);
// Root object
container = new ConflictContainer();
container.resolveByAABB = true;
container.resolveByOOBB = true;
//Player controller
cplayer = new SimpleObjectController(stage, player, 3);
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(3,1,3,1,1);
box.setMaterialToAllFaces(floorMaterial);
box.x = 3*j;
box.y = 2;
box.z = 3*i;
container.addChild(box);
break;
case 1 :
box = new Box(3,1,3,1);
box.setMaterialToAllFaces(floorMaterial);
box.x = 3*j;
box.y = 2;
box.z = 3*i;
container.addChild(box);
box = new Box(3,3,3,1);
box.setMaterialToAllFaces(wallMaterial);
box.x = 3*j;
box.y = 4;
box.z = 3*i;
container.addChild(box);
break;
case 2 :
box = new Box(3,1,3,1);
box.setMaterialToAllFaces(goalMaterial);
box.x = 3*j;
box.y = 2;
box.z = 3*i;
container.addChild(box);
break;
case 3 :
box = new Box(3,1,3,1);
box.setMaterialToAllFaces(floorMaterial);
box.x = 3*j;
box.y = 2;
box.z = 3*i;
container.addChild(box);
box = new Box(3,3,3,1);
box.name = "crate_"+i+"_"+j;
box.setMaterialToAllFaces(crateMaterial);
box.x = 3*j;
box.y = 4;
box.z = 3*i;
container.addChild(box);
break;
case 4 :
box = new Box(3,1,3,1);
box.setMaterialToAllFaces(floorMaterial);
box.x = 3*j;
box.y = 2;
box.z = 3*i;
container.addChild(box);
player = new Box(3,3,3,1);
player.setMaterialToAllFaces(playerMaterial);
player.x = 3*j;
player.y = 4;
player.z = 3*i;
container.addChild(player);
playerCol=j;
playerRow=i;
break;
}
}
}
// Adding
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 Keyboard.LEFT :
playerRotation=+9;
playerAngle+=90;
break;
case Keyboard.RIGHT :
playerRotation=-9;
playerAngle-=90;
break;
case Keyboard.UP :
movingCrate=null;
playerAngle=Math.round(player.rotationY*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;
dRow=1;
dCol=0;
break;
case 180 :
dRow=0;
dCol=1;
break;
case 270 :
//dRow=1;
dRow=-1;
dCol=0;
break;
}
if (levels[playerRow+dRow][playerCol+dCol]==0||levels[playerRow+dRow][playerCol+dCol]==2)
{
// the player can move
playerMovement=-1;
}
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=-1;
}
}
}
break;
}
}
}
public function updateEvent(e:Event):void
{
if (playerRotation)
{
player.rotationY+=playerRotation*Math.PI/180;
if (Math.abs(Math.round(player.rotationY*180/Math.PI))%90==0)
{
playerRotation=0;
}
}
if (playerMovement)
{
switch (playerAngle)
{
case 0 :
player.x += playerMovement;
break;
case 90 :
player.z += -playerMovement;
break;
case 180 :
player.x += -playerMovement;
break;
case 270 :
player.z += 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(player.x*10)/10)%3==0)||(playerAngle%180!=0&&(Math.round(player.z*10)/10)%3==0))
{
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(goalMaterial);
}
else {
movingCrate.setMaterialToAllFaces(crateMaterial);
}
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;
var a:Number = -player.rotationY;
var cx:Number = player.x+Math.cos(a)*r;
var cz:Number = player.z+Math.sin(a)*r;
var cy:Number = player.y+10;
controller.setObjectPosXYZ(cx,cy,cz);
//look at player box
controller.lookAtXYZ(player.x,player.y,player.z);
//correct camera angles
var cprotY:Number = player.rotationY;
cprotY=Math.round(player.rotationY*180/Math.PI)%360;
if (cprotY<0)
{
cprotY+=360;
}
if (cprotY>180)
{
camera.rotationX = camera.rotationX + (90*Math.PI/180)*Math.sin((cprotY%180)*Math.PI/180);
}
camera.rotationY = camera.rotationY+90*Math.PI/180-player.rotationY;
}
public function onEnterFrame(e:Event = null):void
{
controller.update();
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.75);
frame.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
frame.graphics.lineStyle(0, 0x7F7F7F);
frame.graphics.drawRect(pd, pd, camera.view.width, camera.view.height);
frame.graphics.endFill();
}
}
}