Wednesday, July 01, 2009
I've found myself defending oop recently, and at the same time bemoaning the lack of good oop tutorials with regards game development.

Rather than promising to write a full blown tutorial, as to be honest there's no way I'll stick to it, after around 3 parts at most I'll be bored stupid, I thought I'd try and explain the structure behind an existing game which we've already posted the source to. So it may be an idea to open this link in it's own tab.

Ready ? Ok, let's go.

opCFlow.png


Look at that, made with a free package so you get the watermark, nothing's too cheap for you dear reader.

This at heart is how I've structured all my games since starting with as2. It only varies in that there are sometimes more classes in there, the actual hierarchy never changes.

Ok lots of code here is never that great to read, but there's no way around it, sorry,

package {
    import Classes.Init;
    
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;

    [SWF(width="600", height="400", frameRate="35", backgroundColor="#000000")]

    public class Main extends Sprite{

//---------------------------------------------------------------------------------------
// Properties
//---------------------------------------------------------------------------------------
        private static var instance:Main;
        private static var __parent:DisplayObject;
        private static var stage:Stage;
        private static var init:Init;
        
//---------------------------------------------------------------------------------------
// Static ( Singleton )
//---------------------------------------------------------------------------------------
        public function Main(){
            if(instance){
                throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
            } else {
                instance=this;
            }        

            instance=this;
//When we are running from our preloader, comment this out
            waiting();
        }

//---------------------------------------------------------------------------------------
// Public
//---------------------------------------------------------------------------------------
        public override function toString():String {
            return "Main";
        }        

//---------------------------------------------------------------------------------------
        public function waiting():void{
            addEventListener(Event.ADDED_TO_STAGE,mainAddedToStage);
        }

//---------------------------------------------------------------------------------------
// Getters
//---------------------------------------------------------------------------------------
        public static function getInstance():Main {
            return instance;
        }

//----------------------------------------------------------------------
        public function getMainMovie():DisplayObject{
            return __parent;    
        }

//----------------------------------------------------------------------
        public function getStage():Stage{
            return stage;    
        }

//----------------------------------------------------------------------
        public function getInit():Init{
            return init;    
        }

//---------------------------------------------------------------------------------------
// Private
//---------------------------------------------------------------------------------------
        private function mainAddedToStage(e:Event):void{
            stage=this.stage;
            stage.showDefaultContextMenu=false;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.quality=StageQuality.LOW;
            stage.stageFocusRect=false;

            __parent=this.root;
            
            init=new Init();
        }


//---------------------------------------------------------------------------------------
    }
}

Hopefully this should be fairly straight forward ( I did actually grab it from somewhere else when looking for an as3 version which matched what I was doing in as2, so sorry original author, I can't tell anymore what's yours and what's mine ). We're basically waiting around until this instance is added to the stage ( If you try and read some properties before it's technically been created then you're going to get errors. ) and then running the mainAddedToStage method. Importantly we have some getter methods set up here, as we need them ( More later ). This is our document class, and as such it has a "direct" link with the swf ( For want of a better term ). From now on throughout every other class, any reference to stage or Main is obtained from this class.
The very last line you'll see we create a new instance of the Init class ( init=new Init(); ), so let's check that class out.

package Classes {
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.Stage;

    public class Init {
//---------------------------------------------------------------------------------------
// Properties
//---------------------------------------------------------------------------------------
        private var gameController:GameController;
        private var attract:Attract;
        private var soundHandler:SoundHandler;
        
//------------------------------------------------
// System
//------------------------------------------------
        private var main:Main;
        private var mainMovie:DisplayObject;
        private var stage:Stage;
        
//---------------------------------------------------------------------------------------
//Constructor
//---------------------------------------------------------------------------------------
        public function Init(){
            main=Main.getInstance();
            mainMovie=main.getMainMovie();
            stage=main.getStage();

            soundHandler=new SoundHandler();
           
            gameController=new GameController();
            attract=new Attract();
        }

//---------------------------------------------------------------------------------------
// Public
//---------------------------------------------------------------------------------------
        public function toString():String {
            return "Init";
        }        

//---------------------------------------------------------------------------------------
// Getters
//---------------------------------------------------------------------------------------
        public function getAttract():Attract{
            return attract;
        }

//---------------------------------------------------------------------------------------
        public function getGameController():GameController{
            return gameController;
        }

//---------------------------------------------------------------------------------------
        public function getSoundHandler():SoundHandler{
            return soundHandler;
        }

//---------------------------------------------------------------------------------------
    }
}

This again is a bit of a nothingy class. In theory it could be shoved into the Main class with no real harm, the reason I don't is pure lazyness. I like being able to copy the Main class to every new project without having to think about it, i.e aside from the [swf] tag I never have to alter it. It just feels cleaner having that first class do very little.

If you look at our Init class you'll see we just create instances of each class we need ( Refer to our cheapo diagram to help clarify ), and set up some getter methods again ( Just to clarify, a method is exactly the same as a Function, it's just that if you use a function in oop it's called a method instead. I don't know why either ), so other classes can get a reference to these instance's if they need to.

How do I decide which classes sit on which row of the hierarchy ? Main is our document class, so he's at the top and doesn't really do much. Init is Main's love child, and doesn't do much either, he's just creating the actual game classes.
The next row is more interesting. Attract is our front-end. It deals with the title screen, the game over screen, hi-score entry if the game supports it, instructions etc. Basically everything that happens before starting the game and after the game has finished.
Let's jump over to SoundHandler. This is just what it says. It's here because it's used by both Attract and GameController, as both need to have sounds. GameController is a simple class like Init, it handles the creation of all the child classes needed for the game ( Check the diagram ).

Let me try and rationalise why Attract, GameController, SoundHandler are all on the same row, in effect why they're equal to each other. We've already established that Attract and GameController need to be aware of the SoundHandler class as both need sounds. In the grand scheme of things, the Attract class doesn't really need to know about GameController ( Remember Attract is everything but the actual game ) and conversely the GameController really doesn't give a crap about Attract. If one of these classes is working, then the other isn't doing anything, so it makes sense to me that they're on the same row.
Does that mean they never need to chat to each other ? No, but it's at very key points. For example, when the player presses the "Play Game" button in Attract, we kill off all the Attract mode things and then call startGame() method in GameController.

Now we come to something cool. Quite a few times I've seen people moving over to oop, and it's all going well, until they need a reference to a different class. How the hell do we get the reference we need ? No one wants to pass a reference to a class via a constructor, as that's just messy and nasty and really easy to screw up, and it's not like we can be old school and use _root.myMethod(); when we're oop gods.

Notice all my constructors are the same, eg,

//------------------------------------------------
// System
//------------------------------------------------
        private var main:Main;
        private var mainMovie:DisplayObject;
        private var stage:Stage;
        
//---------------------------------------------------------------------------------------
//Constructor
//---------------------------------------------------------------------------------------
        public function GameController(){
            main=Main.getInstance();
            mainMovie=main.getMainMovie();
            stage=main.getStage();
        }

We get a reference to our document class, Main and store it in our local var main. We also store away a reference to our mainMovie ( To be honest I don't think I've used that ref. in as3 yet, it's just a throw back to my as2 code, but I'm a creature of habit so it'll stay there 'til as4 ) and the Stage.

So this is the GameController class, and it's game over, so we want to call the Attract class as he deals with that. This is how we get our reference:

main.getInit().getAttract().gameOver();

Check back with our Main class code up there, see getInit() in the getters section ? It returns a reference to our Init instance. Then look at the Init getters, getAttract() gives us our instance of Attract, and from there we're just calling the method gameOver in the Attract class.
Don't worry if this doesn't make sense straight away, it's quite a bit to get your head around in one go. Basically so long as we have a reference to Main in any class, we can get a reference to any other class no matter how far away from the callee class we are. References aren't a pain in the arse anymore, they're as simple as this.

You may be thinking, how the hell am I going to remember all those getOurInstanceName() method calls. Auto-completion. Flex does all this for you so it's never an issue ( And I'm sure Flash Develop does the same ). I don't know about the Flash IDE, I really don't hold much faith in it doing it, so now may be the time to install Flash Develop and have a play with that.

See we've got the basics of oop hierarchy covered, and I've not had to slip into terms like singleton and composition. Feel free to google both terms, see what they actually mean, and hopefully when you read the flowery descriptions you'll realise that you already get them as we've covered them here.

As always feel free to fire over questions or point out glaring errors in what I've done. Like I said all my games pretty much follow this pattern, which makes sharing code between projects a lot easier plus I'm not having to think about how classes are inter-connected. I'm not suggesting you just blindly copy what I've done, but perhaps plan out your next game using some simple flowchart boxes so you can see where classes should be connected and where it'll be a waste of time to do so.

Squize.

Wednesday, July 01, 2009 1:27:56 AM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [12]  |  Trackback
 Tuesday, June 30, 2009
Our mate Chris has been working away on his first Unity3D powered iPhone game for a little while, and now it's available for free on the iPhone store his mind turned to pimping, and our's to getting an interview so we could pad things out a little without just looking cheap.

snowball_title_screen.png

What I do love is the way Chris just ignores the shit in my questions and just answers the core point without rising to my bait, like I'm 12 and best just ignored.

"How did you find moving from Flash to Unity ? They seem to share a common core, but are different enough to make life interesting. How was it for you ( Darling ) ?"

In some ways it hardly felt different at all, as if they were from the same software family, Unity's version of Javascript is so close to Actionscript (for example when working on the Mac now, I even use Unity's code editor 'Unitron' for my actionscript coding) but when it came to structuring the game it really is very different.
Actually building game mechanics, levels, controls etc is really very intuitive in Unity, however there doesn't seem to be any one agreed way on storing things like player data, global game settings.
The way I ended up doing it all is with a 'gameObject' that doesn't get destroyed when moving between scenes (but this
in itself causes problems when testing then, as you don't have to test from the opening scene, and hence the gameObject hasn't been made yet.)
If someone knows a better way way please do tell me  :)
"iPhone dev via Unity, sex or a drunken wank ( Maybe with tears. Why did she leave, why ? )"

Considering what it does I really don't see how it could be any easier. It gets slightly complicated when you finally move the project over to Xcode, but then Xcode is complicated and that's nowt to do with Unity, is it wrong of me to think that maybe Apple have purposefully made this bit hard to keep the kids out?
It really is very complicated and parts of it would try the patience of a Saint, but as I said this isn't anything to do with Unity.
Maybe someone out there can let me know, is it always this convoluted when dev-ing for consoles? Are there just always weird things you have to do due to copy protection / code signing?

snowball_dev_shot.jpg


"Tell us about going through Apples hoops to get the game on the store, was it just like a great big hug, or more a spit in the eye ?"

It wasn't as bad as I thought it would be truth be told. From first submission to being live in the App Store took around 14 days. We had one
build sent back to us, as we weren't making it clear that the high score table was storing the user's data remotely and also we hadn't specifically requested the users permission to access the internet.
One amazing achievement is though that we have not received one crash report yet, which is testament to how awesome I really am (or that maybe I am working on a lovely high level piece of industry quality middleware with some brilliant engineers...hmm it's probably my awesomeness now that I think about it.)

IMG_0004.PNG

"It's early days yet, but how's the game doing ? Any sort of trend apparent or is it getting lost in the zillion new releases every day ?"

It's done well for what it is, which is a first game, proof of concept. It spent around one week in the top 30 free arcade games and is now in the top 60 or so. It's been installed around 12,000 times and we've had some lovely reviews off people (many of whom commented that is it better and easier to control the Super Monkey Ball on the iPhone).
One interesting point is that we may have got more installs had we charged. This is pure speculation on my behalf, but something I didn't realise is that many of the very popular review sites and magazines for iPhone simply won't cover free games, so even by charging only 59p or something we could conceivably got in pocketGamer, Edge, RetroGamer etc.  So I guess we will be testing my theory on this for
Snowball's Chance in Hell 2  :)

"If badgers had guns, do you think they'd rob post offices ?"

No they'd rob Mash Potato factories.

I hadn't even considered that, damn he's on intellectual fire.

Now you're wet for the game, here's the all important link http://bit.ly/kill5Snowball

Never one to miss the chance to spread the word Chris told me about Kill5's competition. Let's face it, it's not a competition, it's a bribe, but fuck it, who wouldn't want an iPod Touch ?
Read all about it here, http://www.kill5.com/competition/ but come on, I've kinda earned the iPod with this article, so really don't expect to win.
( What should happen if by some fluke I do win ? Everyone is going to think we're big cheaty cheats, I've screwed myself now haven't I ).

A big thanks to Chris for taking the time to do this interview. I'm sure if anyone has some follow up questions he'll be around to tackle them in the comments.

Squize.

Tuesday, June 30, 2009 1:03:16 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Monday, June 29, 2009
This is part 2 of my collection of articles that'll deal with the theory (and the actual creation) of random dynamic levels for a (space)game. In part one we created a damn pretty maze and in part two we're going to modify it a good deal.

If you take a look at part one's output you'll notice that the code generates a pretty random maze. And there we got out first drawback: it's pretty darn random, way to random to assemble a man made structure and not quite what we would expect a spacestation / space ship to look like.

So the first modification I'm going to add will be a method that can reduce the randomness of the maze.

Part 2 - part 1 - making something not that random

My idea is to qualify the randomness by a percentage value, so a random factor of 0 will give you long straight passages that only change direction if the need to (random at that), while using a value of 100 the method will never (as far as it possible) return the same direction twice.

Of course that tiny little addition causes a lot of fuzz and requieres to rewrite a part of the core maze generator function. In part 1 I used a method to get all surrounding cells of a given point, but in order to use the direction modifier we need to use directions instead.

          //... skipped

          while (iCellCount < iTotalCells) {
                
                // get neighbor cells ...
                aCellDirections = myDungeon.getPossibleDirections(pCurrentCell);
                
                // set the cell
                if (aCellDirections.length != 0) {
                    
                    /* old way no direction modification used
                    iRndCell = rnd.Range(0, (aCellNeighbors.length - 1));
                    iRndDir = Dir.getDirFromPoint(pCurrentCell, aCellNeighbors[iRndCell]);
                    */

                    iRndDir = this.getFactoredRandomDir(iLastDir, aCellDirections, iDirChange);
                    pNextCell = myDungeon.getNextPos(pCurrentCell, iRndDir);
                    iLastDir = iRndDir;
                    
                    // remove walls
                    myDungeon.cell(pCurrentCell).setWall (iRndDir, WallType.OPEN);
                    // old way: myDungeon.cell(aCellNeighbors[iRndCell]).setWall(Dir.getOppositeDir(iRndDir), WallType.OPEN);
                    myDungeon.cell(pNextCell).setWall(Dir.getOppositeDir(iRndDir), WallType.OPEN);
                    
                    // store for later use ...
                    aCellStack.push(new Point(pCurrentCell.x, pCurrentCell.y));
                    // old way: pCurrentCell = new Point(aCellNeighbors[iRndCell].x, aCellNeighbors[iRndCell].y);
                    pCurrentCell = new Point(pNextCell.x, pNextCell.y);
                    
                    iCellCount++;
                } else {
                    pPopCell = aCellStack.pop();
                    pCurrentCell = new Point(pPopCell.x, pPopCell.y);
                }
                
            } // while

Some new variables in there: iLastDir (so we can keep track of the last direction used), pNextCell (a point that stores the next cell, basically just a temp. variable), iRndCell has been removed and aCellNeighbours has been renamed to aCellDirections ...

There are two new methdods: getPossibleDirections and getFactoredRandomDir. The first one returns an array that just contains directions that can be used (ie. cells that have not been visited yet), directions are simply stored as 0=North, 1=East and so one (I've encapsulated them into a Dir class to make it easier to read). The second method is a neat example how to make things overly complicated ...

        private function getFactoredRandomDir (iLastDir:int, aListDir:Array, iFactor:int = 50):int {
            
            var rnd:MersenneTwister = MersenneTwister.getInstance();
            var bChangeDir:Boolean = (rnd.Range(0, 99) < iFactor);
            
            var iReturn:int = iLastDir;
            
            // the last used dir is not in the list of possible new directions, so we need to pick a random one ...
            if (aListDir.toString().lastIndexOf(iLastDir.toString()) == -1) {
                iReturn = aListDir[rnd.Range(0, (aListDir.length -1))];
            } else {
                
                // we must change direction AND have at least 2 choices
                if (aListDir.length > 1) {
                    
                    if (bChangeDir) {
                        while (iReturn == iLastDir) {
                            iReturn = aListDir[rnd.Range(0, (aListDir.length -1))];
                        }
                    }
                    
                } else {
                    // just pick what's left ...
                    iReturn = aListDir[0];
                }
                
            }
            
            return iReturn;
            
            
        }


AS3 arrays (in CS3) don't have the nice method I know from c#: contains which would have been oh so easy to use here. I toyed for a fraction of a second with the idea to use a loop to check if a given value would be in an array, but then decided to go ... quick and dirty and use toString and lastIndexOf instead.

The code above is quite easy, so I only do a quick run through it...
- decide if we need to apply a direction change
- if we need to, check if the last dir is in the list of possible dirs, if not just pic a random new (this applies to both states: need to change and keep direction)
- otherwise just pick a random dir until it's not equal the last dir used

That's it.

Running the test app with different values seems to produce the desired results:
0% produces the most possible straight halls,
50% produces somewhat random halls
100% produces a maze with no straight hall at all.

Part 2 - part 2 - still way to much filled space ...

Looking at the maze reveals that there are no free spaces in it, of course we could just paint rooms over it, but I doubt it'll look like what I have in mind.
Randomly removing cells from the map is no option (even if we do check if we would just block a passage), but what about removing cells that just end the passage (ie: dead ends).
Looking at the maze again, it seems that we have (depending on the randomness of direction changes) a lot of them, so our next task would be to find those dead ends and remove them. The first "problem" that comes to me is that each time we remove dead ends, we'd create new ones. In order to clean up the map we only run the "removDeadEnds" methods a couple of times and we're done - right?

Not quite.

If we choose some unlucky values, it might happen that we kill the whole maze and that's something we don't want at all.

I decided to use a percentage of TotalCells that I want to be removed, so if we use 50%, the method should remove half of all available cells.

        public function removeDeadEnds (myDungeon:Dungeon, iRemoveDeadEnd:int = 20):Dungeon {
            
            var rnd:MersenneTwister = MersenneTwister.getInstance();
            
            var i:int;
            var j:uint;
            var iDir:int;
            var iRndCell:int;
            
            var iDeadEndsToRemove:int = Math.ceil((myDungeon.iWidth * myDungeon.iHeight) * iRemoveDeadEnd / 100);
            var iDeadEndCount:int = 0;
            
            var bExit:Boolean = false;
            
            var aTmp:Array;
            
            // the worst case may only return one dead end per run, so
            // to be sure we run it as many times as we may max need
            for (i = 0; i < iDeadEndsToRemove; i++) {
                
                aTmp = myDungeon.getDeadEnds();
                
                if (aTmp.length > 0 && !bExit) {

                    while (aTmp.length > 0) {
                    
                        // this is to make sure that the cells are somewhat even
                        // distributed if we do not use the whole lot
                        iRndCell = rnd.Range(0, (aTmp.length - 1));
                        iDir = myDungeon.cell(aTmp[iRndCell]).getDeadEndDir();
                        
                        myDungeon.cell(myDungeon.getNextPos(aTmp[iRndCell], iDir)).setWall(Dir.getOppositeDir(iDir), WallType.WALL);
                        myDungeon.cell(aTmp[iRndCell]).setWalls();
                        
                        aTmp.splice(iRndCell, 1);
                        
                        if (++iDeadEndCount >= iDeadEndsToRemove) {
                            bExit = true;
                            break;
                        }
                        
                    }
                } else {
                    break;
                }
                
            }
            
            return myDungeon;
            
        }


The comments should explain quite well what's going on in there. Only thing to mention is that I pic random dead ends if there are more available dead ends than cells to remove.

Compile and test ... and viola well done for today. :)

(I must admid it took longer to type all that than to code, so I had a bit of spare time left and coded something alse ;) )

I think that is enough for today, you can see the result (and from the upcoming articles, too) Random Dynamic Level Creation Test page (or here if the server is down).

nGFX

Monday, June 29, 2009 2:34:28 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, June 24, 2009
After a good while of non-techy pimpings I decided to go the x++ route and describe the process of diving into a new game ...

(CE is again on hold due to some gameplay issues I found during testplays - oh well)

There is no name to the game yet, but I can say as much as it will feature random dynamic level creation (as used in Diablo 1 for example), sci-fi themed, using RPG elements and use Unity (though the levels created will look quite different to Diablo, but the idea is the same).
I want to have random levels because that would add to the replay value of the game. I want a single game to last between 15 and 45 minutes. You should be able to start playing and kill the end-boss in that time. After that you should be able just play again, but with different set of maps ...

But to get things rolling a lot quicker I wanted to rapid prototype my ideas using flash/AS3 and then port it to c#.
The reason for this is quite simple: output. In order to "see" what the level will look like without having to worry about how to display them (ie. place 3d walls, create the assets). With using flash i can just grab the data from the generator classes and use the drawing api to quickly throw out a few lines to show the generated data.

Let's dive straight in.

Part 1 - part 1: To cell or to tile ... and is there anything we need before that?

Before I started I thought that it would be nice to move between maps (in case you thought you forgot something), to do so there needs to be a way to store the maps ... I thought of 2 methods:
a) store all visited maps
b) make them reproduceable

I prefer the later one.

So instead of using some built in random number generator I decided to use my "own" that takes a seed and the produces the same set of random numbers when using that seed - perfect.
I found some old AS1 source of some older rnd gen that I could have ported but a quick search showed that there are some more powerfull ones. After bit of research I decided to go with the Mersenne Twister algorithm. As I was too lazy to see if there was an AS3 port, I wrote my own implementation, though you could use any rnd method you want.

The next one was a bit tricky: cell based or tile based?
Tiles are easy to use and to handle, but they are limited to a single spot and mostly do only have a single "state", ie. you can walk on them or not. This might be ok in most cases but for what I have in mind they are too limited.

A cell in my case is a tile with 4 walls (north, east, south and west), if all 4 walls are set, the cell is "closed" ie. a solid rock in a clasical dungeon. The cell also stors a single integer value (so based on it's useage I could store an index in it.
Here is the code for the cell:

package com.gamingyourway.Dungeon {
    
    /**
     * Cell datatype
     * @version 2009 06 24
     * @author nGFX
     */

    public class Cell {
        
        public static const WALL:int = 0;
        public static const OPEN:int = 1;
                
        private var _aWall:Array;    // array of values ... 0=empty ...
        private var _iValue:int;    // stores a single value, ie. room num
        private var _bVisited:Boolean;    // has cell been visited
        private var _bCorridor:Boolean;    // is cell a corridor
        
        
        public function get aWall ():Array { return this._aWall; }
        public function set aWall (value:Array):void { this._aWall = value; }
        
        public function get iValue ():int { return this._iValue; }
        public function set iValue (value:int):void { this._iValue = value; }
        
        public function get bVisited ():Boolean { return this._bVisited; }
        public function set bVisited (value:Boolean):void { this._bVisited = value; }
        
        public function get bCorridor ():Boolean { return this._bCorridor; }
        public function set bCorridor (value:Boolean):void { this._bCorridor = value; }
        
        public function get wallCount ():int {
            
            var i:uint;
            var iCount:int = 0;
            
            for (i = 0; i < this._aWall.length; i++) {
                if (this._aWall[i] == 0) iCount++;
            }
            
            return iCount;
            
        }
        
        public function get isDeadEnd ():Boolean { return (this.wallCount == 3); }
        public function get isUnused ():Boolean { return (this.wallCount == 4); }
        
        /**
         * Creates a new empty (ie. all walls set) cells
         * @param    iValue    used to stor a single bit of info, ie. room num
         */

        public function Cell (iValue:int = 0) {
        
            this._aWall = [0, 0, 0, 0];
            this._iValue = iValue;
            this._bVisited = false;
            this._bCorridor = false;
            
        }
        
        /**
         * sets a single wall
         * @param    iDir    Direction of the wall
         * @param    iWall    value of the wall, 0 is a solid wall, any other value makes it "open"
         */

        public function setWall (iDir:int, iWall:int = 0):void {
            
            this._aWall[iDir] = iWall;
            
        }
        
        /**
         * return the value if the wall in iDIr
         * @param    iDir    direction of the wall to get
         * @return    value of the wall
         */

        public function getWall (iDir:int):uint {
            
            return this._aWall[iDir];
            
        }
        
        /**
         * shortcut for testing if there is a closed wall in iDir
         * @param    iDir    direction to test
         * @return    true if there is a wall
         */

        public function hasWall (iDir:int):Boolean {
            
            return (this._aWall[iDir] == 0);
            
        }
        
        /**
         * if the cell is a dead end, return the direction of the opening
         * @return    the direction of the opening
         */

        public function getDeadEndDir ():int {
            
            var iReturn:int = -1; // not a dead end
            
            if (isDeadEnd) {
                
                if (this._aWall[Dir.NORTH] != 0) iReturn = Dir.NORTH;
                if (this._aWall[Dir.EAST] != 0) iReturn = Dir.EAST;
                if (this._aWall[Dir.SOUTH] != 0) iReturn = Dir.SOUTH;
                if (this._aWall[Dir.WEST] != 0) iReturn = Dir.WEST;
                
            }
            
            return iReturn;
            
        }
        
        /**
         * returns a string representation of the cell
         * @return    a string for the falls of this cell
         */

        public function toString ():String {
            
            var i:uint;
            var strReturn:String = "";
            
            for (i = 0; i < this._aWall.length; i++) {
                strReturn += this._aWall[i].toString();
            }
            
            return strReturn;
            
        }
        
        
    }
    
}


Part 1 - part 2 - Storage and creation

To store the maps generated I wrote a simple Mapa datatype, it'll store a 2d array of cells along with some very basic methods to deal with the data.
The map type also stores width and height in an rectangle, to have an easy way to check if a point lies within the boundaries of the map.
Aditional methods so far:

hasCellInDir (pPos:Point, iDir:uint):Boolean
getNextPos (pPos:Point, iDir:uint):Point
getSurroundingCells (pPos:Point, bUsed:Boolean = false):Array


To create a map (let's call it dungeon for the sake of easiness) I didn't include the methods need to create a dungeon in the map class, instead I wrote a DungeonGenerator class, that returns a filled map class. This way I can mess around with the creation process without messing with the map class.

Part 1 - part 3 - Let's start with a simple maze ...

The most simple representation of a dungeon I can think of is a maze. Mazes are incredibly easy to create and they work oh so well with cells.

The walkthrough to create a maze:
1. create a map of "solid" cells
2. pick a random solid cell as starting point
3. get surrounding solid cells and pick a random one
4. knock the walls between these cells, store the "old" cell in a stack for later use
5. use the cell picked in 3 as new starting point and start over
6. if the current cell has no solid neighbours, pop one from the stack
7. repeat until there are no more solid cells


Easy, eh?

package com.gamingyourway.Dungeon {
    import de.drygoods.Random.MersenneTwister;
    import flash.geom.Point;
    
    /**
     * Dungeon generator
     * @version 2009 06 24
     * @author nGFX
     */
    public class DungeonGenerator {
        
        private var _Dungeon:Dungeon;
        private var _rnd:MersenneTwister;
        
        public function DungeonGenerator(iWidth:int, iHeight:int) {
            
            this._Dungeon = new Dungeon(iWidth, iHeight);
            
            this._rnd = MersenneTwister.getInstance();
            
        }
        
        public function createMaze (iDirChange:int = 100):Dungeon {
            
            var aCellStack:Array = new Array();
            var aCellNeighbors:Array;
            
            var iTotalCells:int = this._Dungeon.iWidth * this._Dungeon.iHeight;
            var iCellCount:int = 1;
            var iRndCell:int;
            var iRndDir:int;
            
            var pCurrentCell:Point = new Point(this._rnd.Range(0, this._Dungeon.iWidth -1), this._rnd.Range(0, this._Dungeon.iHeight -1));
            var pPopCell:Point;
            
            while (iCellCount < iTotalCells) {
                
                // get neighbor cells ...
                aCellNeighbors = this._Dungeon.getSurroundingCells(pCurrentCell);
                
                // set the cell
                if (aCellNeighbors.length != 0) {
                    
                    iRndCell = this._rnd.Range(0, (aCellNeighbors.length - 1));
                    iRndDir = Dir.getDirFromPoint(pCurrentCell, aCellNeighbors[iRndCell]);
                    
                    // remove walls
                    this._Dungeon.cell(pCurrentCell).setWall (iRndDir, 1);
                    this._Dungeon.cell(aCellNeighbors[iRndCell]).setWall(Dir.getOppositeDir(iRndDir), 1);
                    
                    // store for later use ...
                    aCellStack.push(new Point(pCurrentCell.x, pCurrentCell.y));
                    pCurrentCell = new Point(aCellNeighbors[iRndCell].x, aCellNeighbors[iRndCell].y);
                    
                    iCellCount++;
                } else {
                    pPopCell = aCellStack.pop();
                    pCurrentCell = new Point(pPopCell.x, pPopCell.y);
                }
                
            } // while
            
            
            return this._Dungeon;
            
        }
        
    }
    
}


The code of the dungeon generator ... for now only with the maze creation in it.
Note that the variable iDirChange is currently not used, but I'll go over it in the 2nd part of this article.

I think that is enough for today, you can see the result (and from the upcoming articles, too) Random Dynamic Level Creation Test page (or here).

See you next time when I add some direction modifications and take care of dead ends ...

nGFX


Wednesday, June 24, 2009 3:02:34 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [7]  |  Trackback
 Thursday, June 18, 2009
They've been spoken about for a while, even been available in various forms already, but now a couple of big hitters are entering the market.

In the blue corner, GamerSafe, FGL's pretty all encompassing attempt to cover off not just M-Ts but other nice things too.

In the red corner, Mochi and their coins.

Both have their advantages, and both seem to be well thought out and planned ( Although there's not a wealth of info about either yet, early days and all that ).
Is this going to be a VHS vs BetaMax thing, or can the market cope with both ?

This is just a "Look, new things" post. We're really not in a position to review either, or get dragged into a debate about the rights and wrongs of M-T's, and the effect that could have on the market ( Either good or bad ).

We have been discussing them recently and they do have a huge amount of possibilities, but we think they're going to need to be more than a "Buy a new hat for your avatar" style buy throughs, so with what we'd like to do would take time and money, and no one yet knows if there's a market for that ( Or if there is, which system is going to be the BluRay and which the HD-DVD ) ?

Squize.

Thursday, June 18, 2009 4:31:52 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [14]  |  Trackback
 Wednesday, June 17, 2009
Perhaps 'cause it's late, and I'm tired, and I'm coming down from quite a hellish crunch ( All the games got there in time, and the client is pleased. Just thought I should share the good news along with the moans and gripes ), but something is bugging me.

Mike Chambers, well known Flash community facing guy at Adobe, has posted "What new game APIs do you want in the Flash Player ?".

Fantastic!

Why do I feel the need to be churlish about this, I mean it's great news, isn't it ? A chance to air our views to someone whose in a position to push forward ideas to the roadmap.

"I have been learning some game development lately, and building my first game... I think game development and deployment are some of the real strengths of the Flash player, but ones which we haven’t specifically focused on in a while... While working on my game, there were a couple of things I needed to do where additional player APIs could have made the development easier... So, what APIs would you like to see that would make game development easier."

( That's the gist of the post, but please take a minute to read it all ).

Personally, I'd like to see all the things that so many game developers have been asking for since Flash 5. Mike mentions how handy it would be to have a built in pixel perfect hitTest. Surely everyone one reading this right now has been thinking that for years ? Has no one ever requested that feature ?

Why have all the feature requests fallen on deaf ears before ? Flash has been geared towards RIA's for years, with a recent glance at 3D as Away3D et al have helped fill in a short fall with the player, along with the huge ( And really successful ) push to own web video.

But games have been left out in the cold. They're treated like they're almost a happy side effect of the Flash player, that it's not really a real use of Flash ( Noticed that very few of the really high profile Flash developers make games ? Some of them touch on game related mechanics, and do it really well, but actual complete games are very few and far between. I'm sure if they did they would be vocal about the shortfalls in the API and help to have forced a change sooner. Sound got a kick up the arse using a similar approach ).
And yet, GameJacket had a stat that 28% of internet traffic was Flash games ( I can't provide a link for obvious reasons ). The Flash Forwards have a game category. Until a couple of years ago BAFTA did too ( That's now being merged with console games, and in all fairness I can't see Desktop Tower Defence giving Call of Duty a run for it's money ). Millions of people play Flash games, and talk about them, every day
There is a knowledge and interest of Flash gaming, with huge budgets for them, outside of the "Suck and Fuck Street Racing"s.

So why has it taken until now for it to be recognised by Adobe ? Would it really have taken so much effort to not package yet another fucking scroll bar component and give us a hi-score table component just once ? I know there's an excellent one from Mochi, but we're talking first party support here.

Yes to some extent I am being churlish. In effect I'm bitching about Adobe looking to make all our jobs that little bit better, it's just that does it really only take one employee at Adobe to notice the shortfall for things to happen ?

( And yes before you ask I am a bit of a hypocrite as I've never filled in a feature list request for Flash. Maybe all of us who haven't have just got ourselves to blame that we're going to have to wait 'til F11 before getting the sugar ).

Squize.

Wednesday, June 17, 2009 12:21:54 AM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [12]  |  Trackback
 Monday, June 15, 2009
Nothing really new so here's at least something to look at ...

After a good deal of non game related stuff (some WBTs, a lot of non game flash stuff) I finally found the time (and motivation) to continue on Calisto Eclipse my current private joy project, although I must admit that the joy part has left me untill just recently.

There was some oh so boring serverside stuff to do, plus some database layout and it's still not done at all, because I really wanted to have a working game at some point.
Finally the action mode gameplay is working 100%, I just need to fill in the 150+ levels in order to provide at least some sort of progress (just fiddling with times and percentages for a certain tile type, so no real magic behind this).

Story mode needs yet to be "coded", although it just uses things I've done already for the action mode (with some minor variations, so I can create things like "build x structures with size y."

Today was paint the medal day so I thought it might also be a good thing to give you a quick glance at them:
ce_medals.jpg

There are 12 of them all nicely linked to myw (the other thing that dragged me down a good deal).

I guess that's me for now again, but I think it'll be nice to add an ingame screenie too, so here it is:
ce_ingame_action_00.jpg
(scaled down)

Lets just hope I get that done before I die ...

nGFX

 | 
Monday, June 15, 2009 4:10:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, June 14, 2009
We've become a bit lazy here just linking to other peoples stuff and pimping iPhone games. It's partly because we're in the usual state of NDA-ness that means we can't talk about a lot of things ( Such as the great, but very crunch heavy, project we're doing for National Geographic right now ) and partly 'cause all our friends are doing great things which deseve a pimp.

So this is going to be the last one for a while, but it's a great one to go out on. Our friends over at urbaniacs have released their first iPhone game. Want to hear more ? Yeah you sure do.

This is a port of Wedgie Toss 2 ( You can play it on their site right now ), where apparently 14 million wedgie's have been snapped out.

colbert2.png


Look at Stephen Colbert there, oh Stephen how your faux right wing views make me giggle. But I'm going to pick an angle and twang your pants on this fun and yet surprisingly cheap iPhone game ( £0.59, which I guess is $0.99 to the 65% of our readers. See how I tie all our posts together ? When it's done it's all going to make sense, a novel in the form of a blog, with a twist at the end which will blow you away ) which is available here.
Also look where I left a tiny part of the edge of the logo at the top left on that cropped image which I'm too lazy to sort out, but is really bugging me already. How can I take my mind off that, short of playing the game itself ? Another grab should do it,

colbert.png

Look at him go! That's a grace you don't see very often, although you could see it any time if you buy the game, for a tiny $0.99 right here.

Two great games in a week or so, it's never been a better time to buy an iPhone. Well, not right now 'cause the new ones coming out, and let's face it you'll be pissed if you just get the current one.

And on that note, I think I've strained my pimp muscle, so you young 'uns go play whilst I get back to work.

Squize.

Sunday, June 14, 2009 1:18:53 PM (W. Europe Daylight Time, UTC+02:00)  #    Disclaimer  |  Comments [0]  |  Trackback