The other day I got an email from someone who wanted to know how the “infinite” drawing in isotope3 worked. I figured this would be a excellent time both to share some code and get a post done around here.
The source code for this is available under the MIT license
I’m using a technique I first started to use in my game Eater of Worlds, it has since appeared in a few other things I’ve made.
Just piling hundreds of objects in a single DisplayObject causes Flash to redraw all of them each frame. Drawing vectors in Flash is pretty fast, but having to redraw them each frame is a bit unnecessary if they aren’t really changing. Enter cacheAsBitmap, this does exactly what you would expect it to. And it’s great. Until the content changes, then you have to redraw everything again. Taking both the hit of the redraw with the added punishment of creating the cache (not sure how big that is though).
In isotope3 I redraw each and every frame, negating any boost cacheAsBitmap would give.
So what I do is i create a “cache” bitmap, basically the same as flash would do automatically, but this bitmap I’m controlling.
This makes stuff a tiny bit more complicated, since you will need to explicitly tell flash what to draw to the bitmap each frame (or whenever you feel like it really). Another drawback is that if you’re using it to pile in large amounts of objects and want to remove something it gets tricky. A good way to solve this would be to keep the DisplayObjects, but not attached to any visible clip, and updating them as needed.
Enough with the talking for now, here’s a demo (Click it to make it go!)
This is how you set it up:
// initializing the canvas at 500x500, not using the // autoclear and with a full size back buffer. // if you're going to use blurring or some other "destructive" // effect, you can use a smaller back buffer that means // setting a bigger buffer divisor as the fourth argument var _canvas:Canvas = new Canvas(500, 500, false, 1); addChild(_canvas); // this color transform is applied each update(), // here i set the alpha multiplier to .5 making // whatever was in the buffer the last time around // gets faded by that amount var colorTransform:ColorTransform = new ColorTransform(1, 1, 1, .5, 0, 0, 0, 0); _canvas.colorTransform = colorTransform; // a simple blur filter // (it's faster with multiples of two for the blur-setting btw) var blurfilter:BlurFilter = new BlurFilter(4, 4, 1); // feed it in like this, this is too run on each update() _canvas.addFilter(blurfilter);
This is what you do each frame to apply fades, blurs or whatever effects you put in there:
// if you don't apply any effects this isn't even needed. _canvas.update();
To draw something on the canvas you do this:
// draws a white box var box:Shape = new Shape(); box.graphics.beginFill(0xffffff); box.graphics.drawRect(0, 0, 50, 50); _canvas.draw(box);
Get the source, example and flashdevelop project here and try it yourself!
Big thanks to my friend Richard who gave me some feedback on the code making it possible to read for people that are not me.
Comments are very much appreciated!
Awesome. I’ve been trying to figure out this concept for some drawing apps that use a lot of alphas (and a stupid amount of objects 🙂 ). Thanks for the great post and insight!!
Console log said : draw() function is not defined in FLEX Builder 3
ex:
import flash.display.*;
import mx.containers.Canvas;
var box:Shape = new Shape();
box.graphics.beginFill(0xffffff);
box.graphics.drawRect(0, 0, 50, 50);
_canvas.draw(box);
var _canvas:Canvas = new Canvas();
addChild(_canvas);
_canvas.draw(box);
——-
Why ?
Thank’s
Matthieu
It turns out that Flex also has a class that is named Canvas. The Canvas I use here is my custom class, so you need to add that to your libraries and then import com.grapefrukt.display.canvas.Canvas instead of mx.containers.Canvas
I’m sorry for the confusion.
ok 😉 thank’s a lot
Nice. Will put it to good use.