Talking about Sokoban game, 3D, Actionscript 3, Flash, Game development and Users contributions.
Flare3D and Away3D versions of the Sokoban prototype have been published. What’s now?
Directly from InspiritGames we have an Alternativa3D port of the prototype.
It’s a great porting, although it looks a bit “flat” because Alternativa3D does not support light.
In the same blog you can find the Alternativa3D first prototype and even a version with a walking character.
Here it is the source code:
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();
}
}
}
and this is the result:
Which engine would you use?
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.