Why should you care? 96% to 6% CPU usage, that’s why.
Flash Player 8 opened up a lot of boilerplate code via the new Bitmap drawing classes in ActionScript. Usually confined to the nether regions of Director via Lingo, one had to utilize the standard vector drawing tools in Flash. With the combination of runtime drawing with the sprite like nature of MovieClips, Flash enabled pretty powerful tile-based & other gaming engines to be created that were very flexible, and eased a lot of the coding pain that was harder in other graphical engines.
Painful meaning, you had to write a lot more code to get the same result.
Performance Bottlenecks – Many Objects
The one issue, however, is performance. The Flash Player has a few performance bottlenecks, 3 of which tile-based games suffer from. The first is object overhead. Because of the way Flash Player 8 handles prototypes of classes, each Object class has a series of slots for functions and properties, 1 of which is for the proto and prototype properties. These allow the class to know what methods and properties he inherits from his base class as well as who his base class is. Walking up this chain of prototype objects to the main parent (Object) is how inheritance works when you call methods on an extended class; if it doesn’t find it on the immediate prototype, it walks up the chain until it does.
There is significant overhead in creating objects, memory wise. Keeping track of all of the objects slot information, etc. results in a extreme downgrade in performance the more objects you create in Flash, specifically MovieClips. The more MovieClips you create, the slower things get, both in code response time and render time.
Vector Drawings – less detail, high CPU cost
A common response is to simply draw everything dynamically. Why create a tile class object directly (extending MovieClip) or indirectly (extending Object, use MovieClip instance via Composition in class’ constructor), when you can just draw the tiles via the runtime drawing tools into 1 movieclip, and handle mouse interactions via hitTest? Since most tilebased games are event-based, using the keyboard as the primary means of interactivity, the only real hardcore math you are doing is keeping track of where the characters are on the screen, the sprites, and determining if they are allowed to move to another tile.
Utilizing meta-tiles, like Grant Skinner & Brandon Hall have spoken about before, you can significantly reduce collision detection if you need it for a smaller area of objects and tiles, thus lowering the amount of code needed to run for collision detection.
This, however, leads to the 2nd issue. The drawing operations, while fast, are vector only. Most tile-based games utilize bitmaps. Drawing bitmaps would require pixel-precision to duplicate in vector, and vector images are extremely CPU intensive. Another option is to merely just attach bitmap tiles as MovieClips, but then you are back to the same problem of too many MovieClips. Even if they are in no way associated with a class (beyond MovieClip by default), you still incur the overhead.
Bigger vector images do not scroll well either. Even if you don’t utilize strokes (since strokes are rendered differently fills, fills being more efficient when compared to strokes), you will notice the larger and/or more complex you make your vector drawing, the lower your framerate gets. The bigger and/or more complicated the drawing, the less responsive your scrolling maps and code gets.
Bigger Drawing Area, Less Performance
Finally, both of the above are contigent upon size of the drawing area. How big is your map, and how much are you displaying. Unfortunately the 2 play extremely little in performance. For example, if you’re drawing is 600×600, and you utilze a mask to only show 200×200, performance isn’t significantly improved, even if the stage itself is 200×200. The reason for this is even MovieClips with their visibility set to false, non-shown, or off-screen are still rendered. While the combination of visibility to false and putting them helps, it doesn’t gain you very much.
Bigger images render slower, as do many small images taking up the same size area. A larger stage size renders slower than a smaller one. Both of the above have an extreme curve; I don’t have the trig for it, but basically significant performance gains can be gleaned from smaller drawing areas and smaller stage sizes.
This doesn’t necessarely bode well for Flash Lite 1.1/2 either. While utilizing vector drawing tools sounds attractive for a runtime that only gives you 1 meg or less of RAM to play with, you must understand the phones CPU’s are not extremely powerful.
Blitting
Solving the 3 problems above can be solved via blitting & double buffering in combination with cacheAsBitmap and scrollRect.
Defined succintly, blitting is taking 1 or more bitmaps, and combining them into 1 bitmap. So, if you remember the arcade game Pac-Man, imagine the game itself as 1 big bitmap and each element; the maze walls, the dots, the ghosts, the score text, and Pac-Man himself, as individual bitmaps, or pixels. Each is painted onto the same background, in order: walls, dots, Pac-Man, ghosts, and score. To the end viewer they appear is different elements because every frame some of the elements appear to move. In reality, it is just redrawn every frame, and only those areas that have changed.
This is important for Flash Player because of a few reasons. First, Bitmaps take far less CPU to render. While Flash Player since day 1 has been a vector-to-pixel renderer, you now have true bitmap objects that are just that; a series of pixles with different colors on the screen. Drawing & displaying these on todays machines takes very little system resources. In all fairness, bitmaps take more RAM to display vs. CPU.
Secondly, to create a scenario like the above, you are still just drawing and displaying 1 bitmap for what would of been a large number of sprites in Flash Player 7 or below. While sprites (Flash Player’s MovieClip) offer an easier way to animate and code, they are not efficient, ecspecially for an exteremely small runtime web player that utilizes no hardware acceleration, excluding some for newer Macs.
Double Buffering
You can accomplish blitting in Flash by using the new Bitmap classes. You can accomplish blitting for games by using something called Double Buffering.
Defined succinctly in a Flash Player context, double buffering is a technique used display a bitmap on screen that contains a plethora of other bitmaps. One bitmap is drawn in RAM, with additional bitmaps blitted, (copied) onto it. Then, you copy the finished bitmap from RAM and display it on screen as one bitmap.
This is done in screen drawing in other applications to prevent redraw issues, such as seeing the drawing as its being drawn. However, because of Flash’s single-threaded nature, this is mainly done to simplify coding and still getting the performance increase of only displaying 1 bitmap to the screen.
Conclusion
Thus, a developer has the opportunity to create some really compelling tile-based games in Flash Player now that the performance bottlenecks can be overcome via blitting and double-buffering.
Part 2 will show how you utilize blitting and double-buffering in ActionScript 2 in Flash Player 8, and ActionScript 3 in Flash Player 8.5. Additionally, I’ll show you used to do things, and how you can get your CPU usage while scrolling the map to go from 96% to 6%.
What, no love for my double buffering post?
http://www.darronschall.com/weblog/archives/000177.cfm
That’s what comments are for, G! Danke for the link.
i’m just wondering, the drawing api itself draws vector graphics, if someone implemented the same drawing functions to bitmapdata, would it be faster? how much? what do you think?
i’m just wondering: the drawing api draws vector art, afaik. if someone implemented the same drawing functions for bitmapdata, would it be faster? how much? what do you think?
just a little thought:
would/could/should the blitting-double buffer-combo dramatically improve the performance not only of games, but of map-client-engines?
the reasonable thought being:
lovely yahoo-maps beta is nothing but a tile-based engine (true? tracing width/height and ++v leads me to this assumption) and it lacks performance animatedPanning-wise (on my g3-laptop, anyways ;).
anyone follow or is it just me being misled and not being aware of yahoo-map-api implications?
Zooli, not sure; I haven’t done benchmarks on it, but the bitmap one sure would be better performance if you were to move things around, whereas the vector one is a lot more flexible, requires a lot less coding and is way easier to animate.
subHero, you are absolutely correct. If Yahoo! Maps was targeted at Flash Player 8, they could of drastically improved performance and increased not only the response time, but also the refresh rate (framerate) and significantlly cut down on the ‘Google Maps is faster’ reports.
However, they probably started while Flash 8 was in beta, and because of Flash Player 7 hitting 90% penetration by their scheduled release date that is my guess as to why they didn’t target 8… even though they utilized Flex to create the core component, you can still use Flash 8 features in Flex 1.5 even though the compiler is hardwired for Flash Player 7.
I moonlighted the idea last week of utilize the copyPixels function in Flash 8 to load in the YahooMap.swc in Flash 8, and then re-publishing it by copying the map tiles, and then unloading their contents, and finally copying the final result to the stage.
Not only would this use less resources, but it would be signifinatly faster.
Seemed too much work for so little gain, though; at this point, they are better off either funding a 4 week effort to re-writing the engine in Flash 8, and republishing a new .SWC build for Flash developers, and then after that re-writing it in AS3 to get even further performance increases for Flash Player 8.5.
nice article :)….so when are you gonna post the next part….curious to see your implementation, since I’m currently working on a tile-based scroller making heavy use of copyPixel and hitTest methods for the bitmap data obj.
I’m using bitmap.hitTest for a smart tile grid to pixel-level collision system, depending on the form/bitmap that’s in a tile…..it’s working out nicely and getting good performance out of it…but can always use more, so I’m curious about your methods :)
well, i tried it..if someone cant find a better way to refresh the main rectangle you blit into..other than copyPixels or fillRect..its slow if you try to go with a big stage
Ian, that’s nuts, really? A build I have a tile-engine is really fast; copyPixels is working great. I’m only copying pixels to areas that have actually changed via the 2nd parameter, the copy Rectangle. Does yours copy from the whole stage size bitmap?
Hi, sorry…i had to grip some stuff..heres my test
use white cube to add blitted items..blitted items are blitted on to stage..they are 30 frame 3d sequences in ram..stage background is tiled files..only clips are text blocks. I had to spend some serious time trying different things..this uses just copyPixels. In order to solve flashing of main stage bitmap i run movie at 120fps and intervals at 2! har..that seems to give a nice clean refresh!
http://www.mrgamechef.com/blit/
Hi, more new to report on blitting. I have a background made of areas drawn straight to stage..no clips..with 3 levels of bitmap art filled. Im running one set interval which iterates with a for loop through all items blitted to one rect that scales to fill the entire stage. I just want to say this is a way to make a game as its super super fast..shocking. I will put a sample up soon. Basically one set interval and one main rect with other rects blitted…also mouse listener based hit detection(for mouse) and a ‘level shifter’ to re-arrange the actor list to make things draw to different levels if needed.