package
{
import
alternativa.Alternativa3D;
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.materials.FillMaterial;
import
alternativa.engine3d.materials.TextureMaterial;
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
=
10
;
//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;
// 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
// 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
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
);
// 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
var
backBottom:Plane =
new
Plane(
200
*CUBESIZE/
2
,
200
*CUBESIZE/
2
);
backBottom.setMaterialToAllFaces(backBottomTexture);
backBottom.x =
0
;
backBottom.y = -
100
*CUBESIZE/
2
;
backBottom.z =
0
;
backBottom.rotationX =
90
*Math.PI/
180
;
container.addChild(backBottom);
var
backLeft:Plane =
new
Plane(
200
*CUBESIZE/
2
,
200
*CUBESIZE/
2
);
backLeft.setMaterialToAllFaces(backTexture);
backLeft.x =
0
;
backLeft.y =
0
;
backLeft.z =
100
*CUBESIZE/
2
;
container.addChild(backLeft);
var
backRight:Plane =
new
Plane(
200
*CUBESIZE/
2
,
200
*CUBESIZE/
2
);
backRight.setMaterialToAllFaces(backTexture);
backRight.x =
0
;
backRight.y =
0
;
backRight.z = -
100
*CUBESIZE/
2
;
container.addChild(backRight);
var
backFront:Plane =
new
Plane(
200
*CUBESIZE/
2
,
200
*CUBESIZE/
2
);
backFront.setMaterialToAllFaces(backTexture);
backFront.x = -
100
*CUBESIZE/
2
;
backFront.y =
0
;
backFront.z =
0
;
backFront.rotationY =
90
*Math.PI/
180
;
container.addChild(backFront);
var
backBack:Plane =
new
Plane(
200
*CUBESIZE/
2
,
200
*CUBESIZE/
2
);
backBack.setMaterialToAllFaces(backTexture);
backBack.x =
100
*CUBESIZE/
2
;
backBack.y =
0
;
backBack.z =
0
;
backBack.rotationY =
90
*Math.PI/
180
;
container.addChild(backBack);
// 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/
2
,CUBESIZE,
1
,
1
);
box.setMaterialToAllFaces(floorTexture);
box.x = CUBESIZE*j;
box.y =
0
;
box.z = CUBESIZE*i;
container.addChild(box);
break
;
case
1
:
box =
new
Box(CUBESIZE,CUBESIZE/
2
,CUBESIZE,
1
);
box.setMaterialToAllFaces(floorTexture);
box.x = CUBESIZE*j;
box.y =
0
;
box.z = CUBESIZE*i;
container.addChild(box);
box =
new
Box(CUBESIZE,CUBESIZE,CUBESIZE,
1
);
box.setMaterialToAllFaces(wallTexture);
box.x = CUBESIZE*j;
box.y = CUBESIZE*
3
/
4
;
box.z = CUBESIZE*i;
container.addChild(box);
break
;
case
2
:
box =
new
Box(CUBESIZE,CUBESIZE/
2
,CUBESIZE,
1
);
box.setMaterialToAllFaces(goalTexture);
box.x = CUBESIZE*j;
box.y =
0
;
box.z = CUBESIZE*i;
container.addChild(box);
break
;
case
3
:
box =
new
Box(CUBESIZE,CUBESIZE/
2
,CUBESIZE,
1
);
box.setMaterialToAllFaces(floorTexture);
box.x = CUBESIZE*j;
box.y =
0
;
box.z = 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.y = CUBESIZE*
3
/
4
;
box.z = CUBESIZE*i;
box.rotationX -=
90
*Math.PI/
180
;
// 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/
2
,CUBESIZE,
1
);
box.setMaterialToAllFaces(floorTexture);
box.x = CUBESIZE*j;
box.y =
0
;
box.z = CUBESIZE*i;
container.addChild(box);
player =
new
Sphere(CUBESIZE/
2
,
16
,
16
,
false
,playerTexture);
conplayer.addChild(player);
conplayer.visible =
true
;
conplayer.x = CUBESIZE*j;
conplayer.y = CUBESIZE*
3
/
4
;
conplayer.z = CUBESIZE*i;
conplayer.rotationX -=
90
*Math.PI/
180
;
container.addChild(conplayer);
playerCol=j;
playerRow=i;
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
Keyboard.LEFT :
playerRotation=+
9
;
playerAngle+=
90
;
break
;
case
Keyboard.RIGHT :
playerRotation=-
9
;
playerAngle-=
90
;
break
;
case
Keyboard.UP :
movingCrate=
null
;
playerAngle=Math.round(conplayer.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=-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.rotationY+=playerRotation*Math.PI/
180
;
if
(Math.abs(Math.round(conplayer.rotationY*
180
/Math.PI))%
90
==
0
)
{
playerRotation=
0
;
}
}
if
(playerMovement)
{
switch
(playerAngle)
{
case
0
:
conplayer.x += playerMovement;
player.rotationY -=
18
*Math.PI/
180
;
break
;
case
90
:
conplayer.z += -playerMovement;
player.rotationY -=
18
*Math.PI/
180
;
break
;
case
180
:
conplayer.x += -playerMovement;
player.rotationY -=
18
*Math.PI/
180
;
break
;
case
270
:
conplayer.z += playerMovement;
player.rotationY -=
18
*Math.PI/
180
;
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.z*
10
)/
10
)%CUBESIZE==
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(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.rotationY;
var
cx:
Number
= conplayer.x+Math.cos(a)*r;
var
cz:
Number
= conplayer.z+Math.sin(a)*r;
var
cy:
Number
= conplayer.y+r;
controller.setObjectPosXYZ(cx,cy,cz);
//look at player box
controller.lookAtXYZ(conplayer.x,conplayer.y,conplayer.z);
//correct camera angles
var
cprotY:
Number
;
cprotY=Math.round(conplayer.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
-conplayer.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
);
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();
}
}
}