I converted scrolling background to a bitmap, which now uses more memory, but scrolls much faster, how/why? - actionscript-3

So I'm in the process of making an as3 game with a scrolling cave background. I have it set up to randomly generate a 30x30 cave (900 tiles). I would generate the cave then add all of the tiles as children to a "Background" movieclip. I was having some issues with it lagging so I decided to convert the background to a bitmap. Before I did this trace(System.totalMemory); output a value of around 20,000,000. Afterwards it's around 28,000,000, however the lagging/background-scrolling issues I had seem to have stopped. Why would it use more memory, and why would it alleviate my scrolling issues despite this? Here's the important part of the code.
//My cave is 1800 x 1800 pixels
var bitMapData:BitmapData = new BitmapData(1800, 1800);
//Drawing the cave to a bitmapdata
bitMapData.draw(background1);
var bitMap:Bitmap = new Bitmap(bitMapData);
//Removing all of the tiles from the background
while(background1.numChildren > 0) {
background1.removeChildAt(0);
}
//adding the bitmap to my background
background1.addChild(bitMap);
Any insight is greatly appreciated.

See, drawing a MovieClip is always done through vector renderer, this involves querying its structure, querying display list and more, also in case those MCs of yours have uneven scale (unequal and not in the line of powers of 2) even bitmap rendering is slowed. Having one Bitmap instead of 900 MCs lowers display list traversal time by a great margin (900 vs 1 - isn't it a decent improvement?). Of course, bitmaps occupy more memory than MCs, but this is same old memory vs performance issue that every programmer hits sooner or later. Don't worry about this 8M bitmap, just don't make too many bitmaps this big for mobile platform.

Related

AS3: Disposing of cacheAsBitmap bitmaps?

I've got a large, detailed, interactive vector object with dynamic text that will frequently translate horizontally from off the screen onto the screen when the user needs to look at it, then back off the screen when the user is done. If I set myVector.cacheAsBitmap = true before translating it and myVector.cacheAsBitmap = false after translating it, what happens to all of those bitmaps that are generated each time? Do I have to dispose of them myself?
Adobe help about Bitmap caching:
Turning on bitmap caching for an animated object that contains complex
vector graphics (such as text or gradients) improves performance.
However, if bitmap caching is enabled on a display object such as a
movie clip that has its timeline playing, you get the opposite result.
On each frame, the runtime must update the cached bitmap and then
redraw it onscreen, which requires many CPU cycles. The bitmap caching
feature is an advantage only when the cached bitmap can be generated
once and then used without the need to update it.
If you turn on bitmap caching for a Sprite object, the object can be
moved without causing the runtime to regenerate the cached bitmap.
Changing the x and y properties of the object does not cause
regeneration. However, any attempt to rotate it, scale it, or change
its alpha value causes the runtime to regenerate the cached bitmap,
and as a result, hurts performance.
Conclusion
If you make a simple translational movement along the x or y axis, your bitmap is created only one time.
Do I have to dispose of them myself?
It seems that you can't touch the bitmap cache only used internally by Flash player.

Speeding up masks AS3

I'm currently doing the following when applying a mask to a MovieClip:
mc1.cacheAsBitmap = true;
_mask.cacheAsBitmap = true;
mc1.mask = _mask;
Which works great, however...
mc1 is a complex vector animation, and cacheing it as a bitmap in order to mask it has pretty big memory implications from what I can see, and have read.
Is their another way to implement masks? Or a way to optimise the usual solution?
Thanks
edit
Both the mask and mc1 are MovieClips, and they have been added to the stage, the mask is a gradient.
I am using Flash CS6, both movieclip and mask are added to the timeline, where they are being animated
You can use http://www.greensock.com/blitmask/
Quote from the documentation:
Can’t I just set the target DisplayObject’s cacheAsBitmap property to true and get the same result? Why use BlitMask?
If you set a DisplayObject’s cacheAsBitmap property to true, Flash takes a bitmap capture of that object so that when you move it (only
altering the x and/or y properties), the text and vectors don’t need
to be re-rasterized again before being rendered to the screen.
However, Flash would still need to concern itself with extra pixels on
every frame if you’re masking them to only show a small portion of the
area. BlitMask, however, only cares about that smaller masked area
(after the initial capture of course) which alleviates Flash from
having to even think about the extra pixels.

Spritesheet with mask or separate image files?

I'm making an animation of a 2D character that can walk, run, jump, bend,...
Would it be better to load one big 'spritesheet' with all the animations and just use a mask, or would loading separate files (walk, run,...) be better because you're not using a mask on such a big image every frame?
I'm not using the Stage3D features with a framework like Starling because I think the normal flash display API is fast enough and has much less bugs than the relatively new GPU frameworks.
Blitting just the character (using lock(),copyPixels(),unlock()) works pretty well.
private function updatePixels():void{
//update sprite sheet copy position based on the frame placements ons prite sheet
position.x = spriteSourceData[currentFrame].x + offset.x;
position.y = spriteSourceData[currentFrame].y + offset.y;
//draw into the bitmap displayed
displayData.lock();
displayData.fillRect(displayData.rect, 0x00FFFFFF);//clear
displayData.copyPixels(sourceData, spriteData[currentFrame], position);//copy new frame pixels
displayData.unlock();
}
//a bit about vars:
position:Point
spriteSourceData:Vector.<Rectangle> - from parsed Texture Packer data
offset:Point - front view and side view animations weren't always centred, so an offset was needed
displayData:BitmapData - pluging into a Bitmap object displayed
sourceData:BitmapData - the large sprite sheet
currentFrame:int - image index on the sprite sheet
I've done this on an older project writing a custom class loosely following what I've learned from Lee Brimelow's tutorial series Sprite Sheets and Blitting (Part 1,Part 2, Part 3)
In short, you'd use two BitmapData objects:
a large sprite sheet
a small image to display just the character (size of the largest character bounding box) to copy pixels into
In my project I had a character with front and side animations and for the sides I've used one set of animations and used the Matrix class to flip(scale and translate) the side animation accordingly. I've used TexturePacker to export the image sequence as a sprite sheet and the frame data as well as a JSON object. There is native JSON support now, so that's handy. Texture Packer isn't free but it's really worth the money (affordable, fast and does the job perfectly). I haven't used Flash CS6 yet but I imagine it's also possible to import your image sequence and export a spritesheet with the new feature.
In my experience the rule "the simpler the display list the better the performance" generally applies. Which means you should use the most specific display object that will do the job (don't use a Sprite when a Shape would be sufficient or favor Bitmaps over vectors where it makes sense).
The most extreme version of this is to only have one Bitmap display object on the stage and use copyPixels to draw all game objects into it every time you want to update the screen. It doesn't really matter what the source in the copyPixel call is, it could either be a large BitmapData acting as a sprite sheet or a small BitmapData objects representing a single frame in an animation. This method is really fast and you could easily have many hundreds of objects on screen at the same time. But using copyPixels means you can't scale or rotate a game object, so for those cases you would have to fall back to the much slower draw() method. Of course this single Bitmap method is not suitable for games where you need to attach mouse events to specfic objects in the game, but works well for shoot'em ups or platform games.
To answer your question, I think you will get better performance by using a single Bitmap display object to represent the player and a collection of BitmapData objects for all the animation frames. Then you can just change the Bitmap's bitmapData property to the frame you want to display. You can still load a large spritesheet png and then plit it up into a series of BitmapData objects during the initialization of the game.

Flash/AS3 Framerate in tile-based game is low, despite all tiles being converted to a single bitmap

I'm working on a small game in Flash (AS3) that generates levels using small tiles.
The location,width,height and other properties of the tile are stored in an array upon generation. Each tile is added to the same container movieclip. When all tiles have been generated, the container movieclip is converted to a bitmap, all tiles are removed from the stage, and the original container is removed from the stage and then deleted. The bitmap is the only remaining "graphic" on the stage, aside from the player.
This yields far better performance than allowing all 60,000+ tiles to be rendered individually during gameplay; however, the framerate still reduces as the number of tiles is increased. This makes no sense, as all the tiles are added to a single bitmap that is always the same size, regardless of the amount of tiles.
With 20,000 tiles during generation, the game runs at the full FPS, but with 60,000 it runs relatively choppy, probably around 4-5 FPS.
I've removed collision detection and any/every script that runs through the tile array to rule out the possibility that some other CPU intensive part of the script is lagging the framerate.
Any idea why, despite the fact that all tiles have been removed from the stage and their container is deleted, the game is still running slow even though the background bitmap contains the same amount of data regardless of the number of tiles generated?
Here is the last part of the level generation algorithm which converts the container movieclip to a bitmap and then removes all the tiles:
var temp_bitmap_data:BitmapData = new BitmapData(this.stage_background_mc.width,this.stage_background_mc.height);
temp_bitmap_data.draw(this.stage_background_mc);
this.stage_background_bitmap = new Bitmap(temp_bitmap_data);
main_class.main.stage.addChild(this.stage_background_bitmap);
for (var block in blocks_array)
{
//every block in blocks_array has a child that is the actual graphic of the tile
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
if (blocks_array[block]["type"] == "bg_block")
{
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
blocks_array[block]["block"] = null;
}
if (blocks_array[block]["type"] == "path_block")
{
//path_blocks have a second child in addition to the first one that's already been removed. the second child is the only other child
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
}
}
this.stage_background_mc = null;
[Edit]
Here is a picture of the game to give you a better idea of what's going on:
[Update:]
Even removing the final created bitmap from the stage, ending up with only 1 child on stage, and setting that removed bitmap to null doesn't improve the speed.
A couple of thoughts.
First, you're sorta half taking advantage of AS3's quick work with blitting. You've got the right idea about having only one single Bitmap on the stage, but the steps before (adding DisplayObjects to a MovieClip and the doing draw on that MovieClip) isn't the fastest process. For one thing, BitmapData.draw is slower than BitmapData.copyPixels (here is a post on that). One of the best ways to get speed is to pre-blit all of your graphics, and store them as BitmapData. Then, keep Object references (containing position, etc) for each graphic. In your render loop, run through each object, and use copyPixels to copy the graphic's pixel information to the appropriate positon in your single, on-stage Bitmap. This way, all slow BitmapData.draw commands have happened upfront, and now you are just pushing pixels, which Flash is really fast at.
That process isn't without its downsides, however. For instance, you can't do easy transforms with it. You'd have to pre-blit all frames of a rotation, for instance, in order to rotate the individual graphic (since you can't rotate a BitmapData, and you aren't using draw on a DisplayObject). Still, it is mighty fast if you can live with the limitations.
Here is a post that serves as a tutorial of the process I explained above. It is old, but informative none-the-less.
Finally, 60,000 is a very large number. Flash isn't exactly a "speed demon." No matter how optimized, eventually you'll hit a limit. Just something to keep in mind.
Oh, and this additional post gives some great tips on performance in Flash.

HTML Canvas: How to address latency between user interaction and draw events?

I'm working on a game that allows players to click on a card and drag it across the screen in any random direction. There are a total of 64 100x80 overlapping cards on a 800x800 canvas at any one time and each one is a procedural draw. As some of you probably suspect, canvas doesn't like redrawing that entire canvas for every move. To work around this, I'm utilizing a buffer canvas to draw the card and then attempting to paint that buffer canvas to the main canvas using drawImage(). To ensure there is no drawing buildup, I clear the region of the canvas associated with where I plan to drawImage() using a clearRect().
The problem I'm experiencing is that because the (x,y) coordinates used for the clearRect() and drawImage() are coming from the location of the mouse, if the user moves too fast, the coordinates will differ from the time drawImage() was last executed to the time clearRect() is called during the next draw sequence. The result is residual draw from the last sequence - proportionate to how fast the card is being dragged.
I tried maintaining the (x,y) coordinates from the drawImage() and using those (instead of the current mouse location) for the clearRect() in the next sequence. However, now instead of residual draw being shown, residual we have residual clear (erase).
Thoughts on how I can address this?
NOTE: My animation rate is handled using RequestAnimationFrame and not SetInterval().
Assuming your canvas is static during the drag drop operation, a pretty easy way to get a good increase in performance would be to just cache the rendering.
In other words, when a drag drop operation begins, save the current canvas into another one. Stop all rendering except for the one involved with dragging the card. Now, whenever you need to repaint, simply repaint from your copy-canvas. Since you're basically just copying from one to another, it should be pretty fast.
On each processing cycle, you would take the current position of the dragged card, fill that with data from the copy, then redraw the dragged card in the new position.
Other approaches you could try would be to use some kind of a placeholder for the drag. For example, consider using a same-sized DIV which you display while dragging. This should have the benefit of not requiring to touch the canvas while dragging and thus also run a better performance for it.