Diesel & Battlefield: ActionScript 3 Blitting Engine for Tile-Based Games

Diesel is a blitting engine for Flash Player 8.5 using ActionScript 3. Uses 1 bitmap to paint to vs. using many DisplayObjects in an effort to utilize less CPU & RAM.

Skip to Introduction if you want to know more about Diesel, or read on for background as to why I’m posting this.

Contents

Preface

I was originally using this project as a part 2 & 3 followup to my blitting post, but realized it is a ton of work. Even getting simple benchmarks down on alpha software is pointless because many memory bugs are fixed in later versions, rendering your previous benchmarks worthless. For example, I’ve found a bug with flash.display.Loader where, if you issue a ton of loads, say over 1900, each load allocates almost a meg of memory. The problem is, even if you delete the loader as well as what it loads, the memory isn’t freed. This is known and will apparently be fixed in a later build.

Not to mention I’m still learning ActionScript 3, so my style of coding has changed the more I learn, making it hard to keep 2 different approaches to a problem in sync: using Sprites vs. blitting to 1 bitmap.

I will say this with confidence; blitting is far more scaleable than using a multitude of Sprites. While the memory usage for blitting is far below what the Sprites use, the processing isn’t what I’d hope it’d be. Additionally, I’d forgotten just how much RAM bitmaps can take. So, even if you make a 2880×2880 blank, transparent bitmap in RAM, it still takes about 44megs.

I still believe, however, that blitting is the future of Flash games, and all I need to do is optimize the Diesel engine a bit more, and she’ll be a more attractive alternative to utilizing Sprites for game development.

My original goal in posting was to show my older version of Battlefield, a simple tile-based map engine based on Sprites, and one based on Diesel. A milestone I had reached as getting the TileMap, a base class, to using blitting only, and scrolling via double-buffering (copying pixels from a larger bitmap, not-shown off-screen). While this made the map scroll really fast, when I started adding Sprites, it still kept a good refresh rate, but started using way more processor than I had experienced in earlier tests on a smaller scale using Flash Player 8.

Frustrated, I realized I had to re-write even all of the sub-classes in Battlefield that rendered sprites, as well as the main walking character. I did so at the cost of not updating the older Sprite one with which to do benchmarking at a later date. Don’t care, though, because again, I feel blitting is worth spending more time on perfecting and optimizing.

So, without further adu, I present a really early build of Diesel, a blitting engine, and Battlefield a simple tile-based engine example that uses Diesel.

TOP

Introduction

With the addition of Bitmap classes in Flash Player 8, developers now have the ability to utilize blitting and double-buffering techniques to create resource efficient gaming engines in the Flash Player. Diesel is a set of ActionScript 3 classes that provide a conveinent display engine to take advantage of these new player features.

TOP

Why should I care?

Diesel uses 1 bitmap to draw to vs. hundreds of MovieClips. This results in a more scaleable engine, allowing for more moving sprites, lower usage of RAM & Processor, and better refresh rates.

TOP

What’s wrong with MovieClips for games?

While MovieClip’s are conveinant to code & design with, they are not efficient when dealing with a multitude of bitmaps for games. They also do not scale well when you need to create many of them, and have them all move on the screen at the same time. Finally, large bitmaps in Flash traditionally have not scrolled very fast when used as tile-based game backgrounds. You either have to use 1 large bitmap that is pre-rendered, or you can use tiles in the traditional sense, but neither is an optimal solution for games.

Big bitmaps are not an ideal solution for a couple reasons. First off, it’s not dynamic; you have to create this before hand. While you can load it in dynamically, you have to use MovieClips atop it to generate any effects. Secondly, even if you mask a certain area of the screen, the rest of the bitmap is still drawn the screen, taking up a lot of processor & ram and sacrificing a good refresh rate (smoothness of the animation).

For tile based games, you have 2 solutions. Either draw all of your tiles as multiple MovieClips, and have all of them created in one parent MovieClip. When moving your map, you simply move the main MovieClip that houses them. While this makes coding easy, it suffers from resource usage, namely reduced refresh rate, and it gets worse the more tiles you create. This is even before you start putting gaming sprites on the screen.

Your other solution is to create the tiles on the fly based on the direction the character in the game moves. While this is a lot more scalable than the above, allowing you to create bigger maps, you suffer from redraw speed when creating the new tiles. The creation & destroying operations that you use on the tiles takes up a lot of processor, reducing the continual smoothness of your animations.

TOP

How is Diesel better?

It uses a technique called double-buffering. By using 1 bitmap, you solve a bunch of issues MovieClips have traditionally caused. First, you have 1 bitmap, not hundreds. Each sprite in your game is represented as a data object, but it’s bitmap data is copied to the main big bitmap. All sprites are copied to this main big bitmap. This big bitmap is actually not shown, but is off-screen and not in the Display List. A portion (or all of it) is copied to an on-screen bitmap that is repainted when something moves or changes.

This uses significantly less RAM because each sprite in your game is actually just a data object vs. a Sprite or MovieClip. You store basic information like x and y position as well as width and height as BitmapSprites. They are then added to the BitmapDisplayObject, much like you add MovieClips to the Display List. BitmapDisplayObject is just a flash.display.Bitmap that renders all of the BitmapSprites added to it’s list of things to draw.

Additionally, the entire bitmap does not have to be drawn. For example, many tile-based games consist of a large map, but only a small portion is shown. For this reason, only a small portion of the map can be shown, and thus drawn, not the whole thing. So, when repainting, only those portions of the screen that need to be redrawn are, not the whole thing, nor things not shown.

TOP

Why not use the Display List in Flash Player 8.5?

In my tests, Diesel uses less RAM, and uses less processor vs. using Sprites and the Display List.

TOP

How do I use it?

Simply import the classes into your project. I’ve done my best to match the syntax like the ActionScript 3 flash.display.DisplayObject syntax.

For example in ActionScript 3, if you want to create a sprite and show it, you do something like:

import flash.display.Sprite;
var my_sprite:Sprite = new Sprite();
addChild(my_sprite);

Diesel’s code works on the same concept of seperating the object from the actual drawing. However, instead of adding your BitmapSprite, the Sprite equivalent, to the normal Display List, you instead create a BitmapSpriteDisplayObject, and add your BitmapSprites to it. The BitmapSpriteDisplayObject class is just a flash.display.Bitmap with optimized code to handle drawing BitmapSprites.

An example of creating a BitmapSprite, and showing it, just like you would create a Sprite to show it, is:

import com.jxl.diesel.view.core.BitmapSpriteDisplayObject;
import com.jxl.diesel.view.core.BitmapSprite;
// create your BitmapSpriteDisplayObject
var bsdo:BitmapSpriteDisplayObject = new BitmapSpriteDisplayObject();
// add it to the Display List so it's shown
addChild(bsdo);

// now, create your BitmapSprite
var my_bSprite:BitmapSprite = new BitmapSprite();
// and add him to the BitmapSpriteDisplayObject
bsdo.addBitmapSprite(my_bSprite);

You can add and remove as many BitmapSprites as you want. Additionally, you can create multiple BitmapSpriteDisplayObjects.

TOP

Conclusion

I am definately interested in contributions, suggestions, and/or criticisms. If you’re seriously interested in helping improve the engine so it performs like Andre Michelle wrote it, and/or taking Battlefield to another level, drop me a line in the comments, and I’ll hit you up with Subversion access.

TOP

Examples

Example of Diesel & Battlefield drawing sprites on a walkable map. Click once on the tiles to give focus, and then use arrow keys to move.

Example of Diesel loading tiles at runtime, extracting the bitmap data from a bunch of PNG’s, and drawing them to the map.

TOP

Source Code

Diesel & Battlefield Source Code

  • SVN
    username: public
    password: public
  • SVN
  • ZIP (beta1) Get latest build from SVN

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.5 License.

TOP

19 Replies to “Diesel & Battlefield: ActionScript 3 Blitting Engine for Tile-Based Games”

  1. Getting the following error when I try to run the second sample:

    TypeError: Error #1009: null has no properties.
    at com.jxl.battlefield.view::DefaultTileMap/com.jxl.battlefield.view:DefaultTileMap$protected::onTileLoadComplete()
    at flash.events::EventDispatcher/dispatchEvent()
    at com.jxl.util::LoaderQueue/LoaderQueue$31$private::onComplete()

    ???

    -erik

  2. Erik, I get it to, just dismiss it. The first 2 bitmaps are corrupted online, but I cannot duplicate the error locally. I got that while I was posting and am stumped. My guess is, while uploading the hundreds of images, one got corrupted.

    Just ignore it, the rest load fine.

  3. Shouldn’t your outter most object be called ‘BitmapSpriteDisplayObjectContainer ‘ instead of ‘BitmapSpriteDisplayObject ‘ as only the former one can contain children going off AS3 syntax? Or am I wrong?

  4. Possibly. The BSDO actually doesn’t really contain anything. It merely extends Bitmap, who extends DisplayObject. Thus, he is both a Bitmap and DisplayObject. While he contains copies of those bitmap sprites you add to it, it actually just paints them to itself.

    I can see how it could be viewed as a container, but when you have Flex on the brain like I do, I don’t really view it as a container since in the Flex Framework, containers actually do physically contain other DisplayObjects. Good point regardless.

  5. Can’t get it to work with the FlexBuilder2 Beta — says ‘definition of base class skinbitmap not found’

  6. You have to manually attach the frameworks.swc to the Project in the new Beta 1.

    In the meantime, I’ll make sure the checked in version is Beta 1 compliant next week.

  7. This rocks — think there will ever be a rotation method added to the bitmapsprite? It would be really useful for tile-based maps, with sprites over them … i tried to mod it myself to draw, and rotate a bmp correctly, but alas my math skills are not so hot. Thanks for your hard work.

  8. Has this project progressed at all? i have written my own blitting engine but am having major issues with CPU usage on large areas with moving objects. I have tested with game areas of 200×200, 640×480, 800×600, with moving 50 moving objects when on the larger maps the fps dropps to 5-10 on a p4 1.8 centrino with 1gb of ram. I wasa wondering if your engine has better performance & if so how do you handle the redrawing fo the entire bitmap each frame.

    Cheers
    Jim

  9. I have not compiled the build beyond beta 1. Additionally, I never optimized the engine fully. As it was strictly blitting, I also never made a DisplayList equivalent to compare performance. Either way, even if something is blited & copied via a scrollRect, if it’s not in the bounds, it shouldn’t be updating.

    In your case, if all 50 are all on the screen, and moving, it should be decent with cacheAsBitmap set for the sprites and scrollRect for the map. Are those being used at all out of curiosity?

  10. Stupidly, i have written my own scroll rectangle bitmap class. I didnt realise that there was that functionality there. I was testing it by blitting all moving objects and background together but now am using blitting for static background objects and using sprites/bitmap objects for the moving objects. While reading your articles i assumed you were using the blitting techniques for all objects not just the background. I would be interested in working together to get a decent blitting engine together as i am interested in seeing what it can do. If you are interested in pooling our efforts get in touch on jim at eltanno dot com

  11. Roughly, majority of the CPU savings is due to blitting or due to bitmap cache? Is the blitting techinique easily accomplishable using AS2.0? You mentioned it being more processor intensive. How severe is it? Thanks in advance for answering. =D

  12. The CPU savings are most prominent when scrolling. The biggest CPU eater in Flash Player 7 and below was when scrolling a map. Whether the map was big or small, if you scrolled even just 1 mc with multiple pieces of content within it, the CPU was pretty harsh, and rocketed based on resolution. Bigger the map, the bigger the hit, but usually exponentially so.

    Initial blitting tests using copyPixels from an off-screen bitmap where you just moved the the Rectangle you were copying from was insanely faster and used little to no CPU. When you start adding Sprites, even via the DisplayObject in Flash Player 9, you’d start to use more CPU again. The best I’ve found so far is to make them all bitmaps, and just redraw the bitmaps on the big one, and then use the same technique of copying. You lose a lot of code freedom because you are no longer dealing with the DisplayList, but if you really need the CPU…

    You could do it in AS2 for Flash Player 8; not hard, but since this announcement, what’s the point? Granted, you could still target the AS2 API in Flash Player 9, but you lose a significant performance adjustment that FP9 could give you.

  13. No choice… I only have Flash 8 Pro to work with.

    btw, blitting cannot be used for isometric maps rite? I don’t see how it can be as efficient anymore with depth sorting… At the very most, i suppose each level can be blitted, but anything that is not flat/floor has to be in its own separate layer as a sprite, and that includes walls/buildings.

  14. Not entirely true; forgot to link to this as well. That’ll allow Flash 8 to publish to Flash Player 9.

    Well, the blitting engine I’m using uses tiny Bitmap Sprites that represent some bitmap. Those bitmap sprites are all drawn to the same bitmap (map) so yeah, you could use isometric too I supposed.

  15. Does anyone know if the flash.display.Loader bug ever got fixed? It doesn’t seem like it – I’m using CS3 Pro and still running into the same memory problems.

Comments are closed.