well, the idea is cool, but i guess, you can't just go and jump to a nonexistent frame, and then add content (at least i did not succeed) ...
i have two ideas for you:
- compile a sufficiently long empty clip (with enough frames to do whatever you like, or multiple ones, with lengths being power of 2 (so you'll have no more than 50% overhead)). spread your bitmaps over the frames, and then use
MovieClip::addFrameScript
, to add a gotoAndPlay(0)
at the last frame.
- create an swf at runtime, using a suitable library, as hxformat (ok, you'll need haXe for that, but that is something i'd suggest anyhow, if you really are into performance), and load it with
Loader::loadBytes
. i'm sure there are similar libraries around for as3 (you'll probably want to be using corelib's png encoder so you can embed the slices into the swf). best would be, to create a movieclip, containing the desired animation as an asset, so you load the clip once, grab the class and then instantiate (makes the operation synchronous).
of course, you could combine both, simply creating an empty clip at runtime, and then filling it up with bitmap data ...
apart from that, i'd have other suggestions:
- put all slices into one sprite, and use
DisplayObject::visible
to do the trick.
- do the conversion on the server from which you distribute the swf (maybe inject it using swfmill or so)
- check out banana slice
i'd also note, that the methods you described using BitmapData::copyPixels
or BitmapData::draw
, if well implemented, usually do perform better at the cost of memory ... this is because flash player rendering, anti-aliasing, caching, clipping and many other things are not optimal at all ... there was a discusion about this here lately ... you might want to search for it ...
well then, good luck ... ;)
edit: well, i agree, that isn't really nice, although setting visibility comes nearly at no cost (as long as you don't force rendering just afterwards) ...
anyways ... the trick is to keep track of the last visible object, like so:
package {
import flash.display.*;
import flash.events.Event;
public class SliceBitmap extends Sprite {
private var _currentFrame:uint = 0;
private var _totalFrames:uint;
private var _playing:Boolean;
public function SliceBitmap(slices:Array) {
for each (var slice:BitmapData in slices)
this.addChild(new Bitmap(slice)).visible = false;
this.getChildAt(0).visible = true;
this._totalFrames = slices.length;
this.play();
}
private function onEnterFrame(e:Event):void {
this.goto((this._currentFrame + 1) % this._totalFrames);
}
private function goto(frame:uint):void {
if ((frame < 0) && (frame >= this._totalFrames)) throw "this should be handled";
this.getChildAt(this._currentFrame).visible = false;
this.getChildAt(this._currentFrame = frame).visible = true;
}
public function play():void { this.playing = true; }
public function stop():void { this.playing = false; }
public function get playing():Boolean { return _playing; }
public function set playing(value:Boolean):void {
if (this._playing != value) {
if (this._playing = value)
this.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, int.MAX_VALUE);
else
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
public function gotoAndPlay(frame:uint):void {
this.goto(frame);
this.play();
}
public function gotoAndStop(frame:uint):void {
this.goto(frame);
this.stop();
}
}
}
and here's some code to test:
var slices:Array = [];
for (var i:int = 0; i < 20; i++) {
var b:BitmapData = new BitmapData(200, 200, true);
b.perlinNoise(4, 4, 4, i, true, false, 7, true);
slices.push(b);
}
this.addChild(new SliceBitmap(slices);