Gaming Your Way

May contain nuts.

Inheritance is your friend.

Let's talk about items in the game prototype (which is actually a bit more than a prototype if I look at it).

One gameplay element is finding keys / codes to open doors (although you can also hack them, but that's another story). In the first version these items were separated into Doors and searchable Items, both with a lot of duplicated code, on the item and on the player object that had to interact with these items.

After everything worked like expected (ie: walk up to a crate, press the action button and wait, find the key, walk to the door and unlock it), I started the second refactoring pass. First thing added was the ItemData class, which holds most of the vital data and exposes them to the editor. ItemData covers basic items and things in the game, a wardrobe you can search through is using ItemData as well as a bed or a crate.


Basic ItemData in place.

I already mentioned that doors are a bit tricky when it comes to making them work with generic code, so adding ItemData values to a door meant some messing. As you can see ItemData contains two fields for interaction: action and secondary (mapped to different buttons) and this also the trouble with doors. Doors (at least in this game) have more than one action, based on the door's current state (locked, closed, etc) plus different actions for the same state. If you stand in front of a locked door, but don't have the key, the action is "hack door" - if you have the key, the action is "unlock door".

Exposing that to the editor is more than a major ball ache, except you want to write your own editor panel - which I very much don't want to.

This is where inheritance comes into play. So the Door (DoorController Class) is inherited from ItemData. The trick is that the code that manages the door's state also changes the "action" of the underlying ItemData. As doors are always work the same way this doesn't have to be exposed to the editor. So when the state of the door is changed the "action" is updated based on the new state. Quick, simple and clean - not as flexible as going through the editor, but that's a small price to pay.

Another (big) advantage is that items and doors now all run through the same code for displaying button hints, tooltips and message boxes, so no special cases to tackle.


For comparision: the door's editor values.

Now that this is done, I'm going to add guards wandering around the map and I fear I also need to get my head around doing a minimap to guide your around (without being a spoiler).

... and with this, "Hail to the king and his epic saga in search for candy".

-- Oliver / nGFX

And with this I killed a perfectly working game.

This post seems to be somewhat out of context, I fear - but if you follow my posts on google+ you know that I've been working on a racing game.

The problem is that this blog needs writing and updates, but it always seems to be an overkill to post the minor updates (mostly just a few lines)... sometimes these become longer post that would well fit in here - this is one of them and to make it more appealing using an rss reader I start with an image...

 

Where am I?

My last post on MTR dealt with the fact that I tinkered with the tiles, mainly allowing tiles that are larger than 1x1, which resulted in a shitload of new possibilities and problems.

Map formats: [,]

As always there's more than one way to fuck things up and I think it starts with the way you handle our map data. Lets start with the basic things a single tile needs to know: the tile to use and in this case the way it is facing (3d and all that).

The most obvious choice would be the 2d array [x,y], it is easy, clean and simple. Placing a tile is a nobrainer.

So we can use aMap[x,y] = Tile;

Any basic tilebased tutorial teaches you that. We need to store a direction in there to and as we're lazy right now the 2d array becomes a 3d array, using the 3rd dimension to store tile and direction.

aMap[x,y, 0] = Tile;
aMap[x,y, 1] = Dir.

Still easy enough. I'll skip the part where you use an object to store the data of a tile.

Now we're adding 2x2 tiles to this map and voila: instant fuckup.
You could just store the pivot of the tile and leave the other map slots empty (not good if you need to test if the place you want to store a new tile in is already used or not).
Or you could store a reference to the pivot - either as id (but then you have too look up where the pivot is) or as coords pointing at the pivot (but then you need to find a way to store the coords).

Map format [] and [,]

Another way to store the map is to just store the tiles as sequence and use a simple int[,] as index. The size of the tile doesn't matter that much this way (but it offers it's own range of trouble, again, I'll skip that part unless someone wants to know).

We'll use a simple struct for storing the data (tile, direction and some meta stuff):
aTiles[index] = new Tile(Tile, Dir [, coords]);

and store the index in the 2d map array:
aMap[x, y] = index;

Getting back the tile needs some more code, but it's still readable:
Tile = aTiles[aMap[x, y]];

The neat thing is, for a 2x2 tile I can now add a single tile to the aTiles array and do whatever pleases me to keep the map in sync. I settled with -(id + 1000), as -1 marks an empty space on the map. So a larger tile will be stored like this:

aTiles[10] = new Tile(1, 0, 10, 5); // meta shows a 2x2 tile ..., also storing coords in here
aMap[10, 5] = 10; // pivot
aMap[11, 5] = -1010; // this place is used, but it's not the pivot
aMap[10, 6] = -1010; // this place is used, but it's not the pivot
aMap[11, 6] = -1010; // this place is used, but it's not the pivot 

This way storing the map is also a bit easier as we just have to spit out aTiles as "[Tile, x, y]" (instead of dumping the whole map).

Of course ...

... the drawback of changing the map format is that the whole game stops working unless you have all the methods back in place and working again - and that's what I'll be doing after this commercial break.

And hopefully I'll rember to post the next dev log here .... otherwise you know where to find updates.

nGFX

Friends and foes

For anyone who's interrested: it's shit weather outside. And cold. And grey. And it rains.

So Nuts and Bolts getting near gold status every minute I thought I might explain how lazy I was this time with the level editor. So lazy in fact, that there is no such thing. As Nuts and Bolts is a puzzle game and is using a fairly simple map structure I thought I could get away with doing the maps in the Flash IDE.

The basic idea was to place Movieclips on a grid and read out the names and positions at runtime.

Here's a screenshot of the first level:
nb_post_ide_howto_00.jpg



The squares and circles are in the background so that I know where to align my Movieclips, you can see the textboxes which provide addtional informations for the parsing routine (name is not used in the game anymore, but I was to lazy to remove it and the last box contains the help screens that should be displayed).

Each of the level elements got a name I use to build the map, so the yellow circles with the white "p" are normal platforms (name:"pl"), the green "e" is the exit and so on. Luckily we can use the same name more than once in as3 so I could just copy and paste elements once I had decided what name they should use...

Here's another screenshot of a later level:
nb_post_ide_howto_01.jpg

All we have to do now is to get a copy of the Movieclip (the level MCs are exported for runtime use) with this:

private function getLevelMC (iLevel:int):MovieClip {
	var myClass:Class = getDefinitionByName("mcLevel_" + iLevel.toString()) as Class;
	var mcReturn:MovieClip = new myClass() as MovieClip;
	return mcReturn;
}

And the run the parser of that MC (just a part of the code, though):

// find platforms 
for (i = 0; i < mcMapTemplate.numChildren; i++) {          
	mcLevel = mcMapTemplate.getChildAt(i) as MovieClip;          
	bVisible = false;     
	x = Math.floor(mcLevel.x / 60);     
	y = Math.floor(mcLevel.y / 60);          
	
	switch (mcLevel.name) {         
		case "pl": // normal platform             
			this._aMap[x][y].p = PLATFORM_NUTS;             
			bVisible = true;             
			break;                     
		case "start":         
		case "start_0":         
		case "start_1":        
		case "start_2":         
		case "start_3":             
			this._aMap[x][y].p = PLATFORM_START; // we'll set the dir later when adding beam's data             
			this._aMap[x][y].d = 0; 
			this._pCurrent = new Point(x, y);
			this._pNuts = new Point(x, y);                          
			if (StrUtil.contains(mcLevel.name, "_")) {                 
				this._aMap[x][y].d = StrUtil.cInt(StrUtil.part(mcLevel.name, "_", 1));             
			}                          
			bVisible = true;             
			break;                      
		// [Skipped a lot of code ...]     
	}      
}

Then the Movieclip can be removed again and I can plot the level from the resulting map data array ...
2011_nb_01.jpg

For this game this was hazzle free way of doing (and changing) the 30 levels.

And with that, I'm getting back to the game, I have some sounds to add before it becomes gold ...

nGFX

Dungeons: Explained better

A bit of a repeat post. Nothing from us for ages, and then when it arrives it's just a rehash. Ages back I did try and explain how we make the dungeons in Knight'sQuest ( FB link ), but using test data images along with poor writing didn't explain it too well I don't think.

Ok, so we have at the basis Olli's dungeon generator code. This creates an array of objects describing a room / corridor. Each room is made up of blocks and blocks are made up of 4x4 tiles. The rooms are made up of a variable number of blocks, so we can have small tight rooms or bigger expansive areas.

When plotting a dungeon ( A generic term, it covers the caves and the new forest ) we look through each room which starts its life as just a collection of 4 digit numbers which are stored in a clock wise fashion ( North, East, South and West ) and each tell us if there's a wall / door / nothing.
For example, if we get the code 0111 that means there are walls to the north, and nothing in any of the other directions ( Little weird 1 meaning an empty space, to be honest I couldn't face refactoring Olli's code ).

Due to the large number of combinations, using a switch / if statement was a non starter, I'd still be typing it now, so we used this cheeky bit of code,

            var directionsAsString:String;             if(location=="caves"){                 directionsAsString="caves_"+northWallValue+eastWallValue+
southWallValue+westWallValue;             } else {                 if(location=="dungeon"){                     directionsAsString="dung_"+northWallValue+eastWallValue+
southWallValue+westWallValue;                 } else {                     if(location=="forest"){                         directionsAsString="forest_"+northWallValue+eastWallValue
+southWallValue+westWallValue;                     }                 }                     }                          try {                 var functionCall:Function=this[directionsAsString];                 functionCall();             }             catch (e:Error){ Debug.trace(directionsAsString,2);                 if(location=="caves"){                     caves_1111();                 } else {                     if(location=="dungeon"){                         dung_1111();                     } else {                         if(location=="forest"){                             forest_1111();                         }                     }                 }             }

Basically we just turn the value into a function call. The try / catch is there in case I've missed one of the possible combinations ( And the trace is so I can find out which and fix it ). Using our current example value from above, and we're in the forest this time, we'd call the function

private function forest_0111():void{

Which is a million times easier than any sort of conditional.

Right we now know what block we need to plot ( Take it as read we know the x/y position of it, this isn't the most fun post in the world as it is without me going into that depth ), how do we store the blocks themselves ?

KQ_darkForest.jpg


In the IDE we have block movieclips, like you can see above. Inside those blocks we have a floorMC and then the tiles. For the floor we just use bitmap draw() to grab it and turn it into a bitmap, and then burn that into the master ground bitmap ( All the floors in the game are just one huge bitmap, so no depth sorting or messing around, it's just a flat bitmap we scroll ).
The beauty of this approach is that the floors are in effect art style, we can drop any image on any pixel position, use blendmodes / alpha / scaling / anything really and because we're just burning it into the ground bitmap all this extra stuff is basically free.

That's the floor covered, next the tiles. Each tile in a block is just a movieclip, with an instance name. See that campfire on the top left block ? That's got the instance name "forest_088", and we just store that in an array with a reference to the bitmap of that image ( We're using the blitter for everything, which means bitmaps ). When plotting a block we loop through all the tile mc's in the block, find out the reference to it's bitmap and create a Bob ( Blitter OBject, ie a sprite ) for it.
In terms of layout, we don't have to be really anal, none of these tiles are pixel perfect aligned, that would be soul destroying, so the plotter rounds things down and most of the time gets it right.
One other slight bit of weirdness before we move on, each instance of a certain tile has to have the same name. Going back to the top left block, notice all the trees are the same ? They are all called "forest_008". Normally we'd never use the same instance name, as that's mental and wrong, but all we're doing is looping through each mc in the block, getting it's x,y position relative to the blocks origin, and then it's .name so we can look up the bitmap reference.

Not easy going I know, sorry. We're nearly there.

Notice we've got 4 blocks all with a north facing wall. To try and make the dungeons look as good as possible we make as many variations of each block as we can face. Before we actually plot them, we pick one at random ( Again, another array, just listing each possible block for each possible combination ).

If you've got this far then well done. Hopefully it explains things better than before.

Squize.

Blitter engine: Benchmarks

Ok, before anyone says "You said you weren't going to do any benchmarks, you said. Wanker" I had a rush of inspiration the other night to improve the blitter engine, so I figured I need to have my own benchmark test to make sure I'm not just wasting my time.

And because I'm a giver rather than a taker, I figured it wouldn't kill me to do a pointless sprite based one just to show how slow they [ Sprites ] are.
Before we go any further, I'm busy working with our new favourite client ( We may even have a game to show next week. Yeah, actually producing something rather than talking about it ), which means I'm knackered, which in turn means the examples are as ugly as you like.
Also it's not a case of getting them all running as fast as possible, it's to show the relative speed between them. We're not trying to break records here, it doesn't matter how high we piss, more how the three approaches compare to each other.

The first test just uses sprites with a bitmap for the scrolling background ( ie, the background isn't wrapped in a sprite, it's just a bitmap added directly to the stage ). For this test we only run a 1000 sprites ( Ha, only. In Flash5 that really would have been a record ).

Test1

Yeah, ugly and not even embedded, but it's only for us to see. All the tests can take a little while, once all the sprites are active you'll see "Finished" and then it's worth checking out the fps.

Next up it's a test using bitmaps, like the scroller they are added straight to the screen. 3000 of the bad boys this time.

Test2

You should roughly be getting the same fps as the sprite test, but with 2000 more objects running ( I get around 31-35, but let's not get too hung up on the actual frame rate, as I'm running snow leopard on a macbook pro and using Firefox as my browser. You more than likely won't be, it's all about the relative speeds ).

Final test, 3000 bobs a blitting, and the scroller background is also being blitted.

Test3

Now for me it runs slightly quicker than test2 in the browser ( I'm not running the debug version in the browser ), but locally the bitmap version ran faster by around 5fps or so.

I'm not overly advocating the blitter approach compared to bitmaps, I'm not trying to sell the blitter engine to you. Bitmaps give you a lot more of everything, you get all the lovely blendmodes, rotation, alpha etc. All the good stuff you don't get in a straight forward copyPixels() engine.
The advantage of the blitter engine is that it's better suited to mobile devices, it will run better on an iPhone than a bitmap approach. Moot point I know, but don't forget we're all going to be writing Android games real soon.
Also the framework for dealing with layers is there and working, if you're using bitmaps then you've got to write your own framework for such things ( And if you do, please post it on your blog so I can get a copy ).

Let's recap as it's late, bitmaps are great, the blitter engine is pretty sweet and sprites are like poking a stick in your eye.

Squize.

Blitter engine

I thought I may as well open source this as it may be useful for some of you.

Let's start with the all important caveats.
I'm not going to be showing you a load [ Or any in fact ] of benchmarks or examples, I can think of nothing more boring to do. Either take it on faith that it's fast, or just use it to look through and nick the bits that may be helpful to you. I'm not trying to prove a point with this that my code is so l33t. I've found it useful, if you do to then cool, we're both winners. If not, well you've not lost anything have you ?

Again another life's too short thing, I really can't be bothered with sorting out a license for this, is it MIT or is it GPL ? I don't really care, it's not something I hold close to my heart, it's a bit of code to do a job. If you do tinker with it and make it better it would be nice to share what you've done, if you make a game using it and you make a ton of money, great. A credit or even a shout about it would be cool, but if not, then I'm not going to hunt you down with an angry mob.
The only thing which would piss me off is people passing it off as they're own, but we've got a wanker free readership here so it's not going to be any of you guys, and there's not a lot you can do about the sort of idiots who would do that anyway.

There may be bugs, there was some experimental iPhone and pixel bender stuff in there which I've just ripped out. If you spot any thing dumb please flag it up, it would be nice to have a fixed version available here for people coming to this further down the line.

Ok, let's go over the usage.

The static Canvas class is the main part of it, it's what makes it tick. To set things up just do a simple,

            Canvas.init(stage,new Rectangle(0,0,600,500),true);
            stage.addChild(Canvas.viewport);
 
stage is your stage ref ( Surprisingly enough ), next up is the size of the canvas ( The canvas is the bitmap which everything will be blitted into, the viewport property ), and are we going to be transparent or using a background ? You decide with a boolean. You can also pass a fill colour as the final parameter if you don't want to use a bitmap as the background.

Next in our hierarchy is the PlayField. Think of this as your container sprite. I don't know about you, but I miss working with layers in as1 via the timeline, so I've always simulated them with container sprites. PlayFields are pretty much that, eg

            var defRect:Rectangle=new Rectangle(0,0,600,500);
            gridPlayField=new PlayField(defRect);
            baddiePlayField=new PlayField(defRect);
            playerPlayField=new PlayField(defRect);

            Canvas.addChild(gridPlayField);
            Canvas.addChild(baddiePlayField);
            Canvas.addChild(playerPlayField);

From memory I don't think the engine actually does anything with the rectangle we pass to it, I think I was planning to do some simple clipping, but never got round to it, but pass it in anyway it doesn't do any harm.

When it comes to rendering the display, the Canvas class loops through all the PlayFields in the order they are added, so the gridPlayField in that example will be plotted first, then the baddiePlayField and so on. It's a simple way of simulating layers / depth.

Finally we're onto the Bob class. These are your Blitter OBjects, your software sprites. To create one,

            var temp:Bitmap=new playerBM();
            bob=new Bob(temp.bitmapData);
            playerPlayField.addChild(bob);

You just pass it the bitmapData you want, and then add it to your PlayField. The Bob class has all the properties you'd expect, and supports animation too ( So bob.gotoAndStop(bob.currentFrame+1) works, check through the class on how to pass it an animated sprite sheet ).
Where possible I've tried to make things as close to the display list as possible, there's no need to be forcing a new syntax onto yourself.

Like the PlayFields these are plotted in order ( The PlayField is basically just a list of its children ), so add them in the depth order you want, exactly like adding children to a sprite.

As with all blitter engines there are restrictions due to using copyPixels, so forget all about rotation and alpha and blendModes. A pity, and I did start with a ComplexBob class that used Draw() for those things, but to be honest it was a real arse ache, and it's quicker to attach the bitmap directly than to use draw ( The downside to that being the bitmaps have to be above the canvas, there's no way to slide them in there between PlayFields ).

There are quite a lot of properties and methods available to you in these classes, auto-complete is going to be your friend with this.

One last thing, the Canvas uses the RENDER event to refresh the screen, so there's no need to call anything in your mainloop, just by altering a bob's x position it'll refresh for you ( If you're not going to use the actual package, I'd recommend having a look at the Render event stuff, you should find it quite useful if you're doing something similar ).

Guess I should just link to it now, download me here.

As always abuse the comments. Just to sound a grumpy shit for one last time this post, this isn't some big open source project that I plan to expand and maintain, if you find bugs or even better come up with fixes, then yeah they'll be added with a great big bag of thanks from me, but this isn't my life's work. Feature requests are going to be ignored to be honest, it is what it is.

Squize.

(Run) DMC

We're at the start of week 3 of the new game, Destroy More Cars, which unsurprisingly is the sequel to our Destroy All Cars game.

It's the first outing for our blitter engine, so I thought I'd touch on that quickly.

dmc_grab1.jpg



If you've read the previous post you'll see there that I recommend a blitter engine for CS5 / iPhone development so I've been working on ours so it's there ready for the next project.

At the core of the blitter is the Canvas class. This holds the bitmap we're plotting to, does the lock / unlock thing, clears the canvas when needed ( By copying the background bitmap on there rather than fillRect ) and calls the children display objects.

Next up is the PlayField class. These are in effect layers. When I code I usually create sprites as holders and add these to the stage in order to simulate IDE layers, the PlayField class is just the same really.

At the bottom of this hierarchy are the building blocks, the Bobs. These are just simple sprites that are plotted to the canvas using copyPixel ( I've started work on a ComplexBob class which uses draw(), slower but it supports all the things that copyPixel can't, such as scale, alpha, rotation etc. Pain in the arse to code though, so slightly on the backburner and I'm just using bitmap's as simple sprites in the mean time ).

To make this truly useful I've tried to copy the existing DisplayObject as closely as possible, so for example if we've got an animated bob we can use bob.gotoAndPlay(bob.currentframe+1), to add a bob to a playField it's as simple as playField.addChild(bob) etc.
Depth sorting is in there too which makes life so much simpler ( The PlayField class is basically a list manager, making sure the bobs are always in the order we want. That's all depth sorting is really, just specifying what order to plot things in ).

One thing I stumbled upon the other day was the very sexy stage.invalidate(); To put it simply it's a way of flagging up the stage has been made dirty ( Altered ). If you have a stage.addEventListener(Event.RENDER,update);
listener, then when a stage.invalidate() is called at the end of the frame just before plotting everything our update method is called ( Via the RENDER event ). This means we don't have to call the update method as we usually would during our enterFrame main loop, in effect it handles itself, like the real display list does.

With using that, Vector lists which we loop through, lock / unlock etc. it all runs pretty quickly. Benchmarks I find are always a bit throwaway unless they're part of a really detailed set of comparisons, it's so easy to put a bit of spin on them to prove your code is the fastest.
Obviously I can't be bothered to do proper benchmarks, so prepare for some spin. DMC is running 6 layers of parallax on a 640x480 screen. It's got a handful of box2D objects ( The images are bitmaps rather than plotted via the blitter ) . In the screen grab above I think it's running 70 rain particles, but when I was testing I cranked that up to 500 just to push things. We've also got up to 80 glass particles ( Those little blue pixels at the top right of the grab ), soft particles for the smoke ( It's the first time I've used for particles for that as opposed to just pre-rendered images ) and there are 20 bits of debris spinning around in 3D, along with car door which rotates around in 3D too. With all that running it didn't drop a frame, stayed at a rock solid 35fps.

I think damage maps may speed things up in certain situations, but I'm more than happy with how it's performing right now, so that can be done if it's needed.

And that dear reader is how our blitter works.

Squize.

Simple Star Wars wipe in as3

I've done this effect to death, used it again in the upcoming DAC ( Whose launch has been delayed due to having to add achievements, luckily someone else is doing that ) so I figured it's time to put it out to pasture and share it around.

'cause we've not been posting as often here, I thought I'd treat everyone to some nice grabs to break up the code slightly.

Basically we want to create a simple gradient rectangle movieclip, like so

swatch_grab.png

And we end up with something looking like this,

gradient_grab.png

A simple rectangle that's slightly bigger than your stage, that fades out to one side. It needs to be bigger than your stage 'cause we want all the gradient part with the alpha blending to be off-screen when we first apply it as a mask.

Next up, the boring old code bit.

package Classes {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.Stage;
    
    import gs.TweenLite;
    
    public class Transition {

//---------------------------------------------------------------------------------------
// Assets
//---------------------------------------------------------------------------------------
        [Embed("../_assets/assets.swf",symbol="transitionMaskMC")]
        private var transitionMaskMC:Class;

//---------------------------------------------------------------------------------------
// Properties
//---------------------------------------------------------------------------------------
        private var playField:Sprite;

        private var grabBitmapData:BitmapData;
        private var grabBitmap:Bitmap;

        private var transitionMask:Sprite;
            
//------------------------------------------------
// System
//------------------------------------------------
        private var main:Main;
        private var mainMovie:DisplayObject;
        private var stage:Stage;

        private var callBack:Function;
        
//---------------------------------------------------------------------------------------
//Constructor
//---------------------------------------------------------------------------------------
        public function Transition(){
            main=Main.getInstance();
            mainMovie=main.getMainMovie();
            stage=main.getStage();

            grabBitmapData=new BitmapData(640,480,false,0);
            grabBitmap=new Bitmap(grabBitmapData);
            grabBitmap.cacheAsBitmap=true;
            
            transitionMask=new transitionMaskMC();
            transitionMask.cacheAsBitmap=true;
        }
        
//---------------------------------------------------------------------------------------
// Public
//---------------------------------------------------------------------------------------
        public function toString():String {
            return "Transition";
        }        

//---------------------------------------------------------------------------------------
        public function grabScreen(callBackArg:Function):void{
            callBack=callBackArg;

            if(playField==null){
                playField=main.getInitObj().getPlayField().transition;
            }

            grabBitmapData.draw(stage);
            transitionMask.x=-160;
            grabBitmap.mask=transitionMask;
            playField.addChild(grabBitmap);
            playField.addChild(transitionMask);

            callBackArg();

            TweenLite.to(transitionMask, 1.5, {x:640, delay:0.2,onComplete:houseKeeping});

        }

//---------------------------------------------------------------------------------------
        public function houseKeeping():void{
            playField.removeChild(transitionMask);
            playField.removeChild(grabBitmap);
        }

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

There's really no way to make code look interesting in a blog is there ?

            grabBitmapData=new BitmapData(640,480,false,0);
            grabBitmap=new Bitmap(grabBitmapData);
            grabBitmap.cacheAsBitmap=true;
            
            transitionMask=new transitionMaskMC();
            transitionMask.cacheAsBitmap=true;

Here in our constructor we're just creating a bitmap which we're going to use when we take a snap shot of the whole screen, and create our transisitonMask ( ie, the gradient mc we've just made ) instance.
The key thing is to turn cacheAsBitmap=true on both, otherwise the gradient mask won't work, it'll just be a boring old normal gradient free mask.

            grabBitmapData.draw(stage);
            transitionMask.x=-160;
            grabBitmap.mask=transitionMask;
            playField.addChild(grabBitmap);
            playField.addChild(transitionMask);

            callBackArg();

            TweenLite.to(transitionMask, 1.5, {x:640, delay:0.2,onComplete:houseKeeping});

This is the guts of what we're doing. Firstly use the always sexy draw() to grab the whole screen, then position the mask so our alpha blended bit is off screen. We want the whole snap shot bitmap to be masked normally at first.
We then simply add both the bitmap and mask to the screen. You'll notice the playField reference there. What I do, as I'm a layer loving kinda guy, is create a simple class that creates all the holders for all the things in a game at the depths I want. It's like codey version of using layers that way. So for your transition "layer", that should be on top of everything else ( You could also add it directly to the stage, same thing, I'm just paranoid that I'll need a layer above the transition for some reason ).
We've got the bitmap, the mask, the bitmap is now masked so all we need to do is cheat, and use the very lovely TweenLite. That just slides our mask all the way across the screen, in effect removing our mask, but with the nice alpha blending on the edge it makes it appear soft. Kinda like in Star Wars.

Notice the callback and the slight delay in the tween in there ? What we do is call the transition method, and then jump back to our main code where we're setting up the screen "beneath" the transition, so it wipes away to reveal our next screen.

[Update: Destroy all Cars is now ( Finally ) live, so you can see it action and see if you want to go to the effort of using it yourself ]

Squize.

Dial Z for Zombie - dev diary

So after the set of articles about random level generation I wanted to put that into use (alas not in the scale I planed it out - mind you) - so I came up with a nice little 3 week project - that was 5 weeks ago.

The basic idea is a simple top/down shooter blended with a good portion of Gauntlet added (hordes of enemies, maybe). And while it's fun to watch levels being created by code it involves a good deal of additional work, like changing the tilesets, adding dirt and stains.

The X entries seemed to be a good idea, so I'm going to publish a few wip builds soon, too (alas not as many as Squize).

In order to see something at all (except the test visuals from the article tests) I needed to convert the cell based dungeons into someting tile based, and write a simple scroller to display the created maps. I decided that each cell should consist of 6 by 6 tiles, so I could use a one tile wide border for the walls (if any) and still have 4 tiles walking space. Next point on the list was the question about how to store the data generated - as I didn't wanted to convert cells/tiles at runtime before they're being displayed. Storing them in an array seemed a good idea, but I wanted to try something new...

Not to mention that converting 50x50 cell dungeon would result in an 300x300 array.

After a few minutes I thought that using BitmapData would be a nice try to store the map, as it'll give me a quite quick direct access 3 dim array (x,y, R,G,B,A) which I could use multiple times. so I used the alpha chanel for the tileset, the red one for the actual tile, blue for pathfinding and green for effects/2nd layer.

Right, why storing a tileset?

In my idea each room has basically the same tiles (ie. walls, doors, corners and floor) and the conversion would be much easier if I would use the same tiles over and over. So I came up with storing tiles in tilesets, which offsets the tiles on the tilesheet.
The creation process is quite easy this way:

First I have to create a tileset and give it a name, say "Corridor".

myTileset = new Tileset("Corridor");

Then add tiles to that tileset, giving it a name and and x/y offset in the tilesheet (I wrote data class for that):

myTileset.addTile(new Tile("empty", 0, 0));
myTileset.addTile(new Tile("Floor00", 1, 0));
myTileset.addTile(new Tile("WallN", 0, 1));
myTileset.addTile(new Tile("CornerInN", 1, 1));


Internally I use the tile's index, but the cell/tile converter just uses the name:

if (!myCell.isUnused) {
                        
    iTile = myTileset.index(strFloor);
    iPath = 0
    iSpecial = 0;
    bmpdMap.fillRect(new Rectangle(xx, yy, iTilesPerCell, iTilesPerCell), this.rgba(iTile, iSpecial, iPath, iTileset));
    
    // walls
    for (i = 0; i < Dir.NUM_BASEDIR; i++) {
        
        if (!myCell.isOpen(i)) {
            cx = xx + aWall[i].x;
            cy = yy + aWall[i].y;
            
            iTile = myTileset.index("Wall" + Dir.shortName(i));
            iPath = 255;    // so you can't walk there (for the bool map pathfinding)
            iSpecial = 0;
            bmpdMap.fillRect(new Rectangle(cx, cy, aWall[i].width, aWall[i].height), this.rgba(iTile, iSpecial, iPath, iTileset));
            
            // door
            if (myCell.hasDoor(i)) {
                
                // door frames are painted "above" the floor, so I use the special layer for that
                iTile = myTileset.index(strFloor);
                iPath = 127;
                iSpecial = myTileset.index("Door" + Dir.shortName(i) + "0");
                bmpdMap.setPixel(cx + aDoor[i][0].x, cy + aDoor[i][0].y, this.rgba(iTile, iSpecial, iPath, iTileset));
                
                iSpecial = myTileset.index("Door" + Dir.shortName(i) + "1");
                bmpdMap.setPixel(cx + aDoor[i][1].x, cy + aDoor[i][1].y, this.rgba(iTile, iSpecial, iPath, iTileset));
                
            } // ToDo: add windows if possible ...
            
        }
        
    }
    
    // ... draw corner and outer coners [skipped]
}

Ah. Nice and easy :)

So by using a different tileset you can easily control the visuals of a room.

Next thing on the list: the scroller - more thinking here ...

I wrote the Scroller class as extension to Sprite so I could add my own sprites and use the Sprites scrollrect for clipping. Adding a Scoller to the stage became easy as 123:

this._Scroller = new Scroller(620, 460, 20, 20); // width, height, tilewidth and tileheight
this._Scroller.name = "scroller";
this._Scroller.x = 10;
this._Scroller.y = 10;

this.addChild(this._Scroller);

this._Scroller.setTileset(this._bmpdTileset, this._TilesetCollection);
this._Scroller.setMap(this._bmpdMap); // the freshly generated map
this._Scroller.setCenter(310, 230);   // alows offsettin the origin, so 0,0 can be at the center of the scroller

this._Scroller.xPos = 0;
this._Scroller.yPos = 0;
this._Scroller.draw();
// updates the visuals of the scroller

the way the scroller is set up (I still need to optimize redrawing, though) makes it possible to use it with tween utils like TweenLite:
TweenLite.to(this._Scroller, 1, [xPos: 100, yPos: 100, onUpdate: this._Scroller.draw});

So after a few days of coding it looks like this:
DialZ_pre_00_small.jpg
(scaled version)

The visibilty test is in place (you can only see the room you're currently in and vector boundaries are created (the green rect in the room, door triggers (blue rect)). The map in the left corner is shwoing the pathfinding bounds (helpfull for testing, too) and will be replaced by a minimap later (circular, hopefully).

Right now I'm writing the vector intersection methods (I'm using math instead of the tiledate for collisions) - so I thing the next entry will feature that.

nGFX

As boring as boring can be

We've had a plan for a while now for gathering the stats from cronusX and displaying them in widgets on a custom page. We weren't allowed to data mine the version of cronusX on Candystand, we're only go to do it in the viral version, which is good 'cause it actually buys us some time to get them done.

We managed to get some data when we were beta testing the game, so there are some figures for test data ( I did a quick post with some stats here ).

First widget is the number of asteroids destroyed, here's a clipped screeny

widget_rock.png


Rather than just having a number and that's it, I'm trying to liven these widgets up by hopefully making them interesting. One thing the uk newspapers love doing is when say a new Dinosaur is discovered, they compare it to either black cabs or double decker buses, as apparently if they just put a figure we can't picture it. Shove a bus next to it, and we get it.

So in the spirit of a dumbed down newspaper article, I thought let's compare the weight of the total number of asteroids destroyed to double decker buses.

Figuring out the value is where it gets boring, and as it bored me I'm just passing it on. We're all about sharing. Plus regular readers will know every single time I put any sort of maths on here I get it wrong, so this post is like a sanity check for my calculations.

How big is an asteroid in the game ? Around 96 pixels. The player ship is around 45 pixels, so my train of thought was to set a real life size for the ship, multiply that by 4, and that would be the cubic size of an asteroid. I figured I'd just compare the ship to something in real life, and a F-15 Eagle seemed a good size. They're 63 feet long so let's pretend our ship is 63 feet long and wide too.
That makes our 96 pixel asteroid 252 cubic feet. In meters that's 76. The reason to covert to meters ? 'Cause this page gives us the some nice weight figures which need meters. Apparently we're looking at 3 tons per cubic meter, therefore our rocks weight is 76*3=228 tons. We're nearly there. All we need now is the all important weight of a bus, and the net never lets you down does it ? I went for unladen which is 12 tons. Almost there.

(numberOfRocks*228)/12

That's it. All this effort just for a stat. I think there are going to be another 8 or so widgets, so I'm going to have to come up with more silly things to compare the stats to. Now best you move along otherwise you're going to be asleep soon.

Squize.