Flash AS3 Speed Tests: Rendering and Update Models

About a week ago I jumped into a discussion on Flashkit about AS3 sprite sheets, rendering, etc. There were a lot of good ideas being thrown around, and I put in my 2 cents on how my current engine works. Originally, back in the AS2 days (and early days of this blog), I did some tests with my original BitmapData caching engines and reported some of the results in a blog entry called Retro Blaster is Coming. In it, I detail how I used an Array of BitmapData objects in place of gotoAndPlay and achieved some very nice results. When I started to create a new game engine in AS3, I consulted Chris Cutler, who is an excellent Flash Game programmer and my partner in crime at my day job. He had created a fully blitted side scrolling engine for the Pixel Chix web site in AS2. After consulting him on his basic methodology, I set out to create my own version is AS3. These were the principals I wanted to follow:

1. I will display ALL game objects (including any text that occupies the same area as sprites and tiles) on ONE canvas. This would require the manipulation and blitting of BitmapData for all game objects and a copyPixels operation to update them to the screen.

2. I would hold all of the sprite sheets in arrays of BitmapData for ease and speed. I call these virtual sprite sheets.

3. I would use the new event model to fire off render events to my game objects.

With those goals in mind, I created my new game engine and the forth-coming game, Pumpkin Man to test it. The engine has been working pretty well for me, but as soon as I participated in the Flashkit discussion I began to wonder just how my current engine compares to other engines. Since this is the most optimized engine I have ever created, I dropped my game development for a few days and began to code up a way to test both screen render speed (using FPS as my units) and a method to calculate the length of time the Event model was taking compared to a straight method call to update objects.

I needed to bombard Squize (from Flashkit and the Gamingyourway.com site), as well as Chris Cutler, Jobe Maker, and Mike Grundvig to find any new ideas for rendering the screen. I discovered two methods I had not tried, so I added them to my test. The first method was to replace the Array that holds the Bitmapdata objects with a single sprite sheet strip. Each game object would be an individual sprite (as opposed to blitting the all to a single sprite). I would use the scrollrect property of the Bitmap object inside the sprite to control the animation. It turned out to not be such a hot idea. I can’t blame any of those above for this method because I just made it up after talking to them. It seems that the individual sprites really slow the render throughput, and the scrollrect seems to be painfully slow given that is had to work on so many individual sprites at the same time. I tried and failed to create a version of this with one shared Bitmap (as to only have to update one scrollrect property) but when I attempted to copyPixels from it, I always got the first frame of animation.

After hitting up Squize a few more times, I came to realize that he was using scrollrect to actually only animate ONE sprite, that being the background and play areas of his great new Geometry Wars-like game (he let me preview it). So, it seems that I was using the scroll rect in a completely wrong manner. After talking to Mike Grundvig, I came to realize, that I needed to figure out a whole new way to attempt to scrollrect through a sprite sheet. What I came up was using the same sprite sheet strip instead of an array, but to still blit them all to a single sprite by changing the copyPixels rect (not the scrollrect property) on each frame to hover over just the bitmap I needed.

Anyway, after finally getting a solid foundation in the 5 different rendering engines I wanted to test, I coded up a Flash App that can be used to test and get the results for different combinations of object counts, rendering methods, and what I call models: using either and event or a method to update objects. In this way I would be able to tell which of my 5 different methods was the best. As an aside, even though I got some great results in some of my tests, I have not tested any of these against other people’s rendering engines, so I have no no idea if these are the 5 best choices to test, but they are 5 of my methods. I am sure there are better methods out there.

Method # 1: Animate with an array. Output to one sprite.
This was my current engine of choice when I began this test. The code for the render() method looks like this:

[cc lang=”javascript” width=”550″]
if (animationFrameCount > animationFrameDelay) {
spriteBitmapDataIndex++;
if (spriteBitmapDataIndex == aSpriteBitmapData.length) {
spriteBitmapDataIndex=0;
}
animationFrameCount=0;
}
animationFrameCount++;
blitPoint.x=x;
blitPoint.y=y;
parentClass.getScreenBD().copyPixels(aSpriteBitmapData[spriteBitmapDataIndex],blitRectangle, blitPoint);
[/cc]

Basically, each game object runs this method to jump to the next frame of animation. The array of BitmapData that makes up this virtual sprite sheet is called aSpriteBitmapData. The index of that array is updated only after animationFrameDelay has passed since the last animation frame change. The blitPoint is always the current x,y of the object, and the blitRectangle is always just this: blitRectangle=new Rectangle(0, 0, 32, 32); All objects blit to a single BitmapData called : screenBD (in my parent SpeedTest class);
Up until now, I had assumed that this would be the fastest method I could come up with.

Model # 2: Animate with an array. Output to individual sprites
The only real conceptual difference between this and #1 is how the game objects are rendered on the screen. I still use a virtual sprite sheet Array of BitmapData to hold the animation. I just have each game object render itself as a sprite to the screen instead of blitting to one BitmapData object. This gives me more control over the the Sprites and allows me to make use of Sprite properties such as rotation and scale is needed. The code for the render() function looks like this:

[cc lang=”javascript” width=”550″]if (animationFrameCount > animationFrameDelay) {
spriteBitmapDataIndex++;
if (spriteBitmapDataIndex == aSpriteBitmapData.length) {
spriteBitmapDataIndex=0;
}
animationFrameCount=0;
}
animationFrameCount++;
displayBitmap.bitmapData=aSpriteBitmapData[spriteBitmapDataIndex];
[/cc]

Instead of blitting to a single BitmapData object, I simply update the BitmapData property of the Bitmap used to display the object on the screen: displayBitmap.bitmapData=aSpriteBitmapData[spriteBitmapDataIndex]; This animation Array is handled the same as above in Model #1. This is essentially the the render model I built in AS2, only in AS2/Flash 8 I used the attachBitmap method of a MovieClip as opposed to changing the reference to the BitmapData on a Bitmap object.

Model# 3: Animate with scrollrect. Output to individual sprites.
This method makes use of a single BitmapData strip inside a Display Bitmap instead of a virtual sprite sheet in an Array. It is a literal sprite sheet. On each frame update the scrollRect property of the Bitmap is updated to the needed positron and it acts like a MASK, just showing the part of the sheet I want for that particular frame.

[cc lang=”javascript” width=”550″]if (animationFrameCount > animationFrameDelay) {
spriteBitmapDataIndex++;
if (spriteBitmapDataIndex == spriteSheetFrameCount) {
spriteBitmapDataIndex=0;
}
animationFrameCount=0;
}
animationFrameCount++;
scrollRectangle.x=32*spriteBitmapDataIndex;
displayBitmap.scrollRect = scrollRectangle;
[/cc]

I had high hopes for this one, but it didn’t turn out as expected. This was not quite as fast as I thought it would be. We’ll examine the results in detail the later on in this article.

.Model # 4: Animate with GAS. Output to individual sprites.
I did this one on a lark. I was frustrated with the results of my pathetic scrollrect experiment above, so I decide to test it against a basic gotoAndStop implementation. I built a MovieClip in the library with all 8 frames and a stop on each frame. I copied the Bitmaps from my sprite sheet to individual MovieClips and added one to each frame. This gave me basically what I would have had in AS2/Flash 8 before I began to use BitmapData.

[cc lang=”javascript” width=”550″]if (animationFrameCount > animationFrameDelay) {
gasMC.play();
animationFrameCount=0;
}
animationFrameCount++;
[/cc]

The code for this render() is very straightforward, it just play()s to the next frame after the appropriate animationFrameDelay has been reached.

.Model # 5: Animate sprite sheet with rect. Output to one sprite.
This is a combination of #1 and #3. I use ONE BitmapData canvas inside one Sprite to blit to, but instead of an virtual sprite sheet array, I use a real Bitmapdata object in memory as the literal sprite sheet. The rect property of the copyPixels operation is manipulated to achieve the illusion of animation. This the one I came up with after consulting Squize, Cutler, Maker, and Grundvig.

[cc lang=”javascript” width=”550″]if (animationFrameCount > animationFrameDelay) {
spriteBitmapDataIndex++;
if (spriteBitmapDataIndex == spriteSheetFrameCount) {
spriteBitmapDataIndex=0;
}
animationFrameCount=0;
}
animationFrameCount++;
blitRectangle.x=32*spriteBitmapDataIndex;
blitPoint.x=x;
blitPoint.y=y;
parentClass.getScreenBD().copyPixels(parentClass.getSpriteSheet(),blitRectangle, blitPoint);
[/cc]

The blitPoint and blitRectangle must be updated each frame to scroll along the sheet and ensure the data is blitted to the correct position on the screenBD canavas.

RESULTS:

My basic methodology for the test was to make sure the only programs running on my machine were Excel and the external .swf player for CS3. I did all of these tests outside of the Browser and the Flash IDE as to not be encumbered by the limitations of each. I wrote the testing program in a way that allows me to perform multiple tests without shutting down an restarting the program, but because I am sure garbage collection would have played a part in changing some of the results, I opted to close and restart the testing app between each run. Each test was run for 1000 frames.

100 Object Test. Below are my results for the first run with 100 objects animating and moving across and down the screen. I have noted the peak frame rate and render frame rates and model times. The model time is calculated through the use of the older get Timer() method because it is the only timing method I could find that would actually give me accurate results (Thanks for your help on this one, Chris Cutler). For the Method model, I take the get Timer() time before I start the loop through all of the objects and again when the loop is complete. I have optimized this loop to the best of my ability. For the EVENT model, I took the get Timer() before the event dispatch, and took one on the line directly beneath. It seems that Flash does call these in a synchronous manner, so it seems to work fine.

Model METHOD EVENT
100 Objects
Render (frame rate) Peak FPS FPS
#1 Array, One Sprite 125 126
#2 Array, Multiple Sprites 125 126
#3 Scrollrect, Multiple Sprites 125 125
#4 GAS, Muliple Sprites 109 109
#5 Sprite Sheet, One Sprite 126 125
Render (frame rate) Avg FPS FPS
#1 Array, One Sprite 124 124
#2 Array, Multiple Sprites 124 124
#3 Scrollrect, Multiple Sprites 124 123
#4 GAS, Multiple Sprites 107 107
#5 Sprite Sheet, One Sprite 124 124
Model Times Peak milliseconds milliseconds
#1 Array, One Sprite 4 11
#2 Array, Multiple Sprites 3 10
#3 Scrollrect, Multiple Sprites 11 10
#4 GAS, Multiple Sprites 1 10
#5 Sprite Sheet, One Sprite 2 2
Model Times Avg milliseconds milliseconds
#1 Array, One Sprite 0.958 0.978
#2 Array, Multiple Sprites 0.0069 0.013
#3 Scrollrect, Multiple Sprites 0.011 0.037
#4 GAS, Multiple Sprites 0.0519 0.065
#5 Sprite Sheet, One Sprite 0.975 0.969
Creation Time milliseconds milliseconds
#1 Array, One Sprite 3 3
#2 Array, Multiple Sprites 5 7
#3 Scrollrect, Multiple Sprites 6 8
#4 GAS, Multiple Sprites 13 13
#5 Sprite Sheet, One Sprite 3 3
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 4747 4915
#2 Array, Multiple Sprites 4788 5050
#3 Scrollrect, Multiple Sprites 5279 5558
#4 GAS, Multiple Sprites 5152 5320
#5 Sprite Sheet, One Sprite 4661 5001

All of the render methods performed very well from an FPS point of view. All of these achieved at least 109 FPS with 100 objects. GAS was the slowest, but all of the others averaged at least 123 FPS no matter which Model was used. It is interesting to note that the average render time for the model was much much lower for the array of sprite versions (especially the event model). The single bitmap blit (#1, and #5) had a much higher average millisecond MODEL run rate. This didn’t seem to effect the frame rate much, as those achieved some of the highest FPS rates.

The average model time difference between Event and Method was was not as significant. In some cases the EVENT was actually a little faster than the METHOD call. What really effected the model execution time was the render() method chosen.

Consistently, object creation time was the close between the two Models, but varied wildly between the different rendering methods, with GAS taking the most time to initially create 100 MovieClip objects. Memory usage

Memory usage was pretty consistent, with the EVENT model versions taking up a little more ram, while not surprisingly, the Sprite Sheet, Single Sprite (Method #5) overall used the least amount of memory (in METHOD model mode).

.500 Object Test. These were conducted in the same manner as the 100 object tests. Note that at 500 objects the scrolled (#3) and GAS (#4) are starting to become unusable.

Model METHOD EVENT
500 Objects FPS FPS
#1 Array, One Sprite 125 125
#2 Array, Multiple Sprites 125 124
#3 Collect, Multiple Sprites 21 20
#4 GAS, Multiple Sprites 25 26
#5 Sprite Sheet, One Sprite 125 125
Render (frame rate) Avg FPS FPS
#1 Array, One Sprite 124 124
#2 Array, Multiple Sprites 124 123
#3 Scrollrect, Multiple Sprites 19 18
#4 GAS, Multiple Sprites 22 23
#5 Sprite Sheet, One Sprite 124 123
Model Times Peak Milliseconds Milliseconds
#1 Array, One Sprite 6 14
#2 Array, Multiple Sprites 2 13
#3 Scrollrect, Multiple Sprites 103 106
#4 GAS, Multiple Sprites 2 12
#5 Sprite Sheet, One Sprite 7 15
Model Times Avg Milliseconds Milliseconds
#1 Array, One Sprite 3.962 4.1
#2 Array, Multiple Sprites 1.015 1.162
#3 Scrollrect, Multiple Sprites 1.086 1.173
#4 GAS, Multiple Sprites 1 1.128
#5 Sprite Sheet, One Sprite 4.028 4.585
Creation Time Milliseconds Milliseconds
#1 Array, One Sprite 9 16
#2 Array, Multiple Sprites 28 36
#3 Scrollrect, Multiple Sprites 29 37
#4 GAS, Multiple Sprites 79 92
#5 Sprite Sheet, One Sprite 10 15
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 5058 5390
#2 Array, Multiple Sprites 5480 5996
#3 Scrollrect, Multiple Sprites 7364 9207
#4 GAS, Multiple Sprites 7767 8830
#5 Sprite Sheet, One Sprite 5033 5308

Again we see that the Event Model is slightly slower in execution speed than the Method Model. We also see that the average execution speed for #1 (Array of Bitmap Data, one display object) and #5 (Sprite Sheet and one display object) is the slowest, but did not affect average frame rate. Those were the fastest versions. It is interesting to note that I might actually choose #2 (array of bitmapData Multiple Sprites) if I was going to have about 500 Sprites on the screen because the frame rate is high, and the average execution speed is the lowest of the three that actually performed well. The execution speed difference would help with things like collision detection and other in game calculations. The down side to #2 is object creation time is the highest of the leading three, so the use of a sprite object pool would be absolutely necessary. Memory usage was pretty good across the board for #1, #2, and #5. These seem to be the best FPS models so far.

1000 Object Test. The same methodology as the 100 and 500 tests was used for this test. ScrollRect (#3) and GAS (#4) are becoming pretty much unusable, and the 1000 frame tests for both took quite a few minutes to complete.

Model METHOD EVENT
1000 Objects
Render (frame rate) Peak FPS FPS
#1 Array, One Sprite 94 93
#2 Array, Multiple Sprites 92 93
#3 Scrollrect, Multiple Sprites 8 8
#4 GAS, Multiple Sprites 11 11
#5 Sprite Sheet, One Sprite 93 89
Render (frame rate) Avg FPS FPS
#1 Array, One Sprite 93 91
#2 Array, Multiple Sprites 91 91
#3 Scrollrect, Multiple Sprites 6 6
#4 GAS, Multiple Sprites 9 9
#5 Sprite Sheet, One Sprite 92 87
Model Times Peak Milliseconds Milliseconds
#1 Array, One Sprite 11 20
#2 Array, Multiple Sprites 5 17
#3 Scrollrect, Multiple Sprites 103 134
#4 GAS, Multiple Sprites 4 26
#5 Sprite Sheet, One Sprite 12 22
Model Times Avg Millisecond Millisecond
#1 Array, One Sprite 8.22 8.682
#2 Array, Multiple Sprites 2.959 3.066
#3 Scrollrect, Multiple Sprites 2.055 2.02
#4 GAS, Multiple Sprites 2.008 2.36
#5 Sprite Sheet, One Sprite 8.707 9.01
Creation Time Milliseconds Milliseconds
#1 Array, One Sprite 29 49
#2 Array, Multiple Sprites 73 92
#3 Scrollrect, Multiple Sprites 71 107
#4 GAS, Multiple Sprites 155 187
#5 Sprite Sheet, One Sprite 29 49
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 5414 6295
#2 Array, Multiple Sprites 6225 7061
#3 Scrollrect, Multiple Sprites 11943 12173
#4 GAS, Multiple Sprites 13479 13037
#5 Sprite Sheet, One Sprite 5369 5644

Consistently, #1 using a Method loop to update the sprites is the fastest frame-rate wise. The arrays of BitmapData consume a little more memory than #5 (Using a Sprite sheet instead of an Array). Both #1 and #5 take about 4x longer of processor time on average to call the rendering functions, but this is more than made up for with the throughput of blit rendering to a single BitmapData object. Creation time is still under 30 milliseconds for #1, and #5.

#2 (Using an array of BitmapData for animation, but rending to 1000 separate sprites is still a contender here, and in pure FPS, it even slightly beats #5. It has a lower execution time (2.9 milliseconds compared to 8+ for #1 and #5); The only drawback to #2 is the creation time for the 1000 objects. It takes 2x as long to initialize them as #1 and #5. Also You can see that the execution times for 1000 objects using the EVENT model, while slightly slower in all areas, is very competitive. There is no absolute clear winner here because while #2 is slightly slower frame rate-wise, the execution time would make it easier to squeeze in more collision detection and AI to your 1000 objects.

5000 and 10000 Object Tests. I lumped these two tests together because the results are very similar, though obviously the frame rates are going down, and the execution times are going up.

5000 Objects

Model METHOD EVENT
5000 / 1000 Objects 5000 5000
Render (frame rate) Peak FPS FPS
#1 Array, One Sprite 24 22
#2 Array, Multiple Sprites 18 18
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 22 22
5000 5000
Render (frame rate) Avg FPS FPS FPS FPS
#1 Array, One Sprite 23 21
#2 Array, Multiple Sprites 17 17
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 22 21
5000 5000
Model Times Peak Milliseconds Milliseconds
#1 Array, One Sprite 44 64
#2 Array, Multiple Sprites 30 48
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 49 56
5000 5000
Model Times Avg Milliseconds Milliseconds
#1 Array, One Sprite 40.971 43
#2 Array, Multiple Sprites 27 26
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 43.442 44.18 84.66 87.435
5000 5000
Creation Time Milliseconds Milliseconds
#1 Array, One Sprite 151 525
#2 Array, Multiple Sprites 601 1322
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 139 528
5000 5000
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 8826 10833
#2 Array, Multiple Sprites 12627 14573
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 8806 9973

10000 Objects

Model METHOD EVENT
5000 / 1000 Objects 10000 10000
Render (frame rate) Peak FPS FPS
#1 Array, One Sprite 12 12
#2 Array, Multiple Sprites 9 9
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 12 12
10000 10000
Render (frame rate) Avg FPS FPS
#1 Array, One Sprite 12 11
#2 Array, Multiple Sprites 8 8
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 12 11
10000 10000
Model Times Peak Milliseconds Milliseconds
#1 Array, One Sprite 88 107
#2 Array, Multiple Sprites 64 85
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 89 116
10000 10000
Model Times Avg Milliseconds Milliseconds
#1 Array, One Sprite 82.572 86.555
#2 Array, Multiple Sprites 59.82 61.61
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 84.66 87.435
10000 10000
Creation Time Milliseconds Milliseconds
#1 Array, One Sprite 273 1764
#2 Array, Multiple Sprites 3847 7279
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 290 1774
10000 10000
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 13062 17108
#2 Array, Multiple Sprites 20627 23298
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 13004 15085

Both the scrollrect and gas rendering engines (#3 and #4) ran too slow for me to get any good calculations. I left to take a shower and 30 minutes later the scrollrect version was still churning along. What is consistent is we cannot get an average frame rate above 23 for 5000 and 12 for10000, and #5 has finally started out outpace #2. The king of FPS is still #1 and the execution time gap between #2 and #1/#5 is closing. It seems that at 5000 objects, individual sprites are no longer a very good idea at all, especially give then 3+ seconds it takes just to initialize and create the objects. Memory usage is starting to become closer between #1 and #5 (arrays vs sprite sheets), and the Event model, while still slower, and more of a memory hog can sustain a pretty even frame rate (if slightly lower than the method call model).

15000 Object Test. This test started to show the seamy underbelly of my testing engine as the #2 tests could not finished because of exception errors in object cleanup and creation. The only number I could get was a max 6 FPS while watching the FPS counter.

Model METHOD EVENT
15000 Objects
Render (frame rate) Peak FPS FPS
#1 Array, One Sprite 8 8
#2 Array, Multiple Sprites 6 x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 8 8
Render (frame rate) Avg FPS FPS
#1 Array, One Sprite 8 7
#2 Array, Multiple Sprites x x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 8 7
Model Times Peak milliseconds milliseconds
#1 Array, One Sprite 130 141
#2 Array, Multiple Sprites x x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 157 180
Model Times Avg milliseconds milliseconds
#1 Array, One Sprite 123 126.972
#2 Array, Multiple Sprites x x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 126 129
Creation Time milliseconds milliseconds
#1 Array, One Sprite 402 3743
#2 Array, Multiple Sprites x x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 426 3695
Memory Usage Kilobytes Kilobytes
#1 Array, One Sprite 17244 21594
#2 Array, Multiple Sprites x x
#3 Scrollrect, Multiple Sprites x x
#4 GAS, Multiple Sprites x x
#5 Sprite Sheet, One Sprite 17211 23592

So, at 15000 objects, the winner is #1, the current engine I am using for my game, by a slight margin. The sprite sheets are starting to consume more memory than the arrays. #1 is also a little faster and takes less time to complete object update executions. 8 Frames per second may not sound like much, but the GAS, individual sprite, and scroll rect versions would be in negative FPS and result in full system crashes if I even attempted them.

Summary
If you didn’t feel like reading all of the above (and who could blame you), here is a summary of the significant findings (at least to me).
The render Models will be referred to by number:

#1 Array of BitmapData, One Sprite for blitting to.
#2 Array of BitmapData, one sprite for each object
#3 scrollrect over sprite sheet, one sprite for each object
#4 GAS, one sprite for each object
#5 Sprite sheet using copyPixels rect, One Sprite for blitting to

100 Onscreen Game Objects Moving and Animating

Fastest Average Frame Rate 124: #1 Event Model/Method Models, #2 Event/Method Models, #3 with Method model, #5 with Method and Event Models.
Slowest Average Frame Rate 107: #4 Both Update Models
Fastest Update Model 0.0069 Milliseconds: #2 Method Model.
Slowest Update Model 0.978 Milliseconds: #1 Event Model
Fastest Object Creation Time 3 Milliseconds: #1 and #5 using both Update Models.
Slowest Object Creation Time 13 Milliseconds: #4 using both Update Models
Least memory used 5033 Kilobytes. #5 Method Model
Most memory used 5558 Kilobytes, #3 Event Model

500 Onscreen Game Objects Moving and Animating

Fastest Average Frame Rate 125: #1 Event Model/Method Models, #2 Method Model Method model, #5 Method Model..
Slowest Average Frame Rate 18: #3 Event Model
Fastest Update Model 1 Millisecond: #4 Method Model.
Slowest Update Model 9.01 Milliseconds: #5 Event Model
Fastest Object Creation Time 9 Milliseconds: #1 Method Model.
Slowest Object Creation Time 92 Milliseconds: #4 Event Model
Least memory used 4661 Kilobytes. #5 Method Model
Most memory used 9207 Kilobytes, #3 Event Model

1000 Onscreen Game Objects Moving and Animating

Fastest Average Frame Rate 93: #1 Method Model
Slowest Average Frame Rate 8: #3 Both Update Models
Fastest Update Model 2.008 Milliseconds: #4 Method Model.
Slowest Update Model 4.585Milliseconds: #5 Event Model
Fastest Object Creation Time 29 Milliseconds: #1 Method Model, #5 Method Model
Slowest Object Creation Time 187 Milliseconds: #4 Event Model
Least memory used 5369 Kilobytes. #5 Method Model
Most memory used 13479 Kilobytes, #4 Method Model

5000 Onscreen Game Objects Moving and Animating (#3 and #4 dropped because they were to slow to even run the test)

Fastest Average Frame Rate 23: #1 Method Model
Slowest Average Frame Rate 17: #2 Both Update Models.
Fastest Update Model 26 Milliseconds: #2 Event Model.
Slowest Update Model 44.18 Milliseconds: #5 Event Model
Fastest Object Creation Time 139 Milliseconds: #5 Method Model
Slowest Object Creation Time 1322 Milliseconds: #2 Event Model
Least memory used 8806 Kilobytes. #5 Method Model (#1 Method was very close)
Most memory used 14573 Kilobytes, #2 Event Model

10000 Onscreen Game Objects Moving and Animating ( #3 and #4 dropped because they were to slow to even run the test)

Fastest Average Frame Rate 12: #1 & #5 Method Model
Slowest Average Frame Rate 8: #2 Both Update Models.
Fastest Update Model 59.82 Milliseconds: #2 Method Model.
Slowest Update Model 129 Milliseconds: #5 Event Model
Fastest Object Creation Time 273 Milliseconds: #1 Method Model
Slowest Object Creation Time 7279 Milliseconds: #2 Event Model
Least memory used 13004 Kilobytes. #5 Method Model (#1 Method was very close again)
Most memory used 23298 Kilobytes, #2 Event Model

15000 Onscreen Game Objects Moving and Animating ( #2, #3 and #4 dropped because they were to slow to even run the test)

Fastest Average Frame Rate 8: #1 & #5 Method Model
Slowest Average Frame Rate 7: #2 Both #1 and #5 Event Models
Fastest Update Model 123 Milliseconds: #1 Method Model.
Slowest Update Model 87.435 Milliseconds: #5 Event Model
Fastest Object Creation Time 402 Milliseconds: #1 Method Model
Slowest Object Creation Time 3743 Milliseconds: #1 Event Model
Least memory used 17211 Kilobytes. #5 Method Model (#1 Method was very close again)
Most memory used 23592 Kilobytes, #5 Event Model

Ok, wow did that take a long time to write, run, and compile into useful (somewhat information). The whole process has taken me over a week to complete, but it was well worth it. I now have enough information to decide which model to use for which kind of application. I like the ease of Event driven update models, but as you can see above they are slightly slower than a method call model. It also looks to me like both the Array Copy Pixels and the sprite sheet Rect copy pixels (#1 and #5 respectively) are my best be for over 1000 objects. I will need to keep an eye out for their render update execution time if I am going to have a lot of other game logic going on.

Anyway, there you have it. You can download the .swf file here to run your own tests if you like. I don’t advise putting it in the browser if you are looking for ultimate numbers, but then again, it might be useful for testing the qualities of the different plug-in versions and browser variations…now I’ll save that for a post Christmas article.

On that note, below is a version you can play with. I don’t advise using over 1000 objects with the GAS or Scrollrect render models though.

I hope this helps you in some way, it sure was a learning experience for me. I am sure you will come across better, more optimized models and engines. If you find one that can do 15,000 objects are higher than 8FPS on a Dual Core Pentium D (3.2 GHZ / 3.2 GHZ) with Radion 7300 card (not the best card, I know) then shoot me an email. I’d love to test it out myself.

-Jeff

2 comments

Leave a Reply