Flash 3D Sokoban Prototype with Alternativa3D – final version

Read all posts about "" game

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:

Download the source code.

Which engine would you use?

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers