Talking about Sokoban game, 3D, Actionscript 3, Flash and Game development.
After the Flare3D prototype using textures, here comes the textured version of the Flash 3D Sokoban prototype with Away3D using, guess what, Away3D.
I used the same textures to make both prototypes as much similar as I can.
This is the source code:
package {
// required flash classes
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Vector3D;
import flash.display.BitmapData;
// required awayed classes
import away3d.containers.*;
import away3d.primitives.*;
import away3d.cameras.*;
import away3d.core.render.*;
import away3d.materials.*;
import away3d.lights.DirectionalLight3D;
public class Main extends Sprite {
private const CUBESIZE:Number=50;
// 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;
// away3d variables
private var view:View3D;// View3D represent the canvas
private var theCamera:SpringCam;// custom camera to manage 1st or 3rd person camera
private var player:Cube;// the player
private var movingCrate:Cube;// the crate which will be pushed
// bitmap datas
private var crateBitmap:BitmapData=new BitmapData(256,256);
private var cratetopBitmap:BitmapData=new BitmapData(256,256);
private var floorBitmap:BitmapData=new BitmapData(256,256);
private var wallBitmap:BitmapData=new BitmapData(256,256);
// some materials
private var floorMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(floorBitmap);
private var wallMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(wallBitmap);
private var goalMaterial:ShadingColorMaterial=new ShadingColorMaterial(0x00ff00);
private var crateMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(crateBitmap);
private var cratetopMaterial:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(cratetopBitmap);
private var playerMaterial:ShadingColorMaterial=new ShadingColorMaterial(0x0000ff);
function Main() {
floorBitmap.draw(new floorPic(256,256));
wallBitmap.draw(new wallPic(256,256));
crateBitmap.draw(new cratePic(256,256));
cratetopBitmap.draw(new cratetopPic(256,256));
// scene setup
view=new View3D({x:320,y:240});
addChild(view);
theCamera= new SpringCam();
view.camera=theCamera;
var light:DirectionalLight3D = new DirectionalLight3D();
light.direction=new Vector3D(CUBESIZE*10,- CUBESIZE*6,CUBESIZE*4);
view.scene.addLight(light);
// 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({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
view.scene.addChild(cube);
break;
case 1 :
cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
view.scene.addChild(cube);
cube=new Cube({material:wallMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
view.scene.addChild(cube);
break;
case 2 :
cube=new Cube({material:goalMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
view.scene.addChild(cube);
break;
case 3 :
cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
view.scene.addChild(cube);
cube=new Cube({material:crateMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
cube.cubeMaterials.bottom=cratetopMaterial;
cube.name="crate_"+i+"_"+j;
view.scene.addChild(cube);
break;
case 4 :
cube=new Cube({material:floorMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE/2,x:CUBESIZE*i,y:0,z:CUBESIZE*j});
view.scene.addChild(cube);
player=new Cube({material:playerMaterial,depth:CUBESIZE,width:CUBESIZE,height:CUBESIZE,x:CUBESIZE*i,y:CUBESIZE*3/4,z:CUBESIZE*j});
view.scene.addChild(player);
playerCol=j;
playerRow=i;
break;
}
}
}
// listeners
addEventListener(Event.ENTER_FRAME,onEnterFrm);
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDwn);
}
private function onKeyDwn(e:KeyboardEvent):void {
if (playerRotation==0&&playerMovement==0) {
switch (e.keyCode) {
case 37 :
playerRotation=-9;
break;
case 38 :
movingCrate=null;
var playerAngle:Number=Math.round(player.rotationY)%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=view.scene.getChildByName("crate_"+(playerRow+dRow)+"_"+(playerCol+dCol))as Cube;
playerMovement=- CUBESIZE/10;
}
}
}
break;
case 39 :
playerRotation=9;
break;
}
}
}
private function onEnterFrm(e:Event):void {
var playerAngle:Number;
if (playerRotation) {
// this is how away3d rotates an object
player.rotationY+=playerRotation;
playerAngle=Math.round(player.rotationY);
if (playerAngle%90==0) {
playerRotation=0;
}
}
if (playerMovement) {
// this is how away3d moves an object
player.moveForward(playerMovement);
if (movingCrate) {
playerAngle=Math.round(player.rotationY)%360;
if (playerAngle<0) {
playerAngle+=360;
}
switch (playerAngle) {
case 0 :
movingCrate.moveForward(playerMovement);
break;
case 90 :
movingCrate.moveRight(playerMovement);
break;
case 180 :
movingCrate.moveBackward(playerMovement);
break;
case 270 :
movingCrate.moveLeft(playerMovement);
break;
}
}
// we need this to know if the player stopped on the destination tile
if (Math.round(player.rotationY)%180==0) {
if (Math.round(player.z)%CUBESIZE==0) {
playerMovement=0;
}
} else {
if (Math.round(player.x)%CUBESIZE==0) {
playerMovement=0;
}
}
if (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) {
//crate over the goal
} else {
// crate outside the goal
}
levels[playerRow+dRow][playerCol+dCol]-=3;
movingCrate.name="crate_"+(playerRow+2*dRow)+"_"+(playerCol+2*dCol);
movingCrate=null;
}
playerRow+=dRow;
playerCol+=dCol;
}
}
// camera management
theCamera.target=player;
theCamera.positionOffset=new Vector3D(0,CUBESIZE*8,CUBESIZE*4);
theCamera.lookOffset=new Vector3D(0,0,- CUBESIZE);
theCamera.damping=20;
theCamera.view;
view.render();
}
}
}
And this is the result:
Next time, I'll compare both engines in the making of textured materials.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.