Hello.
The second Part of the Tutorial is a little bit more tricky. Since we provided one surface of grey tiles in the first part only, we will now improve the whole in that way that each individual tile is filled with the appropriate cutout of the BitmapData of an image file. The tiled Sprites are positioned by one for loop and they represent the picture again correctly. The difference to the original is not to determine because the Sprites lie exactly next to each other. From these tiles we create as last step a ParticleObject to be able to animate it later.
The following sketch is to clarify this compact description a little:
The source code consists of one *.fla file that is mainly used to start the DocumentClass (‘FragmentClassDC.as’). The`FragmentLayer.as’ contains the code to create the tiles from a handed over picture and the code for controlling the animation of the tiles. The class `ParticleObject.as’ creates the respective particle from a square Sprite (‘BitmapDataRectangle.as’), whose BitmapData is replaced from a cut of the handed over picture. The file `QuickLoader.as’ is coherently responsible for loading pictures.
Okay let´s start over:
The creation of the FragmentLayer takes place in the DocumentClass and is similar to the first part, i changed only a few arguments. Note that the container of FragmentationLayer (can also be the Stage) and the loaded Bitmap have to be placed in front of the arguments queue:
// define FragmentLayer arguments private var rectSize:int = 20; // rectangle size private var updateRate:int = 30; // update rate private var dirVector:String = "right"; // animation direction (from - to) private var dispEvent:Boolean = true; // dispatch event when animation has finished private var startNow:Boolean = false; // start immediately private var overlay:FragmentLayer; overlay = new FragmentLayer ( your_container, your_bitmap, rectSize, updateRate, dirVector, dispEvent, startNow); |
The Constructorlooks as follows:
// Constructor public function FragmentLayer (container:DisplayObjectContainer, sourceBM:Bitmap, rectSize:uint, updateRate:uint = 30, dirVector:String = "right", dispEvent:Boolean = true, startNow = true) { this.container = container; this.sourceBM = sourceBM; this.rectSize = rectSize; this.updateRate = updateRate; this.dirVector = dirVector; this.dispEvent = dispEvent; this.startNow = startNow; wLen = container.width / rectSize; hLen = container.height / rectSize; partArray = new Array(); // if two times "true" then start immediately if ( initArea () && startNow ) startEffect(); } |
For the case startNow = true the effect is started immediately. This happen because the called function initArea() returns always a true. In this Example we prefer a delayed Effektstart per MouseClick-Event.
The initialization of the rectangular area:
// Init the rectangle area public function initArea ():Boolean { switch (dirVector) { case "left" : updateLeft(); break; case "right" : updateRight(); break; case "up" : updateUp(); break; case "down" : updateDown(); break; default : updateRight(); // call left as default break; } return true; } |
We have passed dirVector = right so the creation of the tiles is managed by updateRight(). This function arranges the tiles in a way that is resulting in an fragmentation effect from right to left. Each tile is defined by createRect():
// particle movement right to left private function updateRight ():void { for (var i:uint = 0; i < wLen; i++) { for (var j:uint = 0; j < hLen; j++) { var xPos:int = (i * rectSize); var yPos:int = (j * rectSize); createRect (xPos, yPos); } } } |
Each Bitmap stores its picture information as BitmapData. The loaded image wich we have passed to the Constructor contains BitmapData as well and we copy it into the tile-Sprites:
// Fill the fragment pieces private function createRect (xPos:Number, yPos:Number):void { // count rectangles count++; // create rectangle with blue (default) Bitmap inside var cr:BitmapDataRectangle = new BitmapDataRectangle(rectSize); // target rectangle var rect:Rectangle = new Rectangle(0, 0, rectSize, rectSize); // target section of the source image var pt:Point = new Point(xPos, yPos); rect.x = pt.x; rect.y = pt.y; // copy BitmapData to Byte stream var bytes:ByteArray = sourceBM.bitmapData.getPixels(rect); bytes.position = 0; //destination rectangle var destRect:Rectangle = new Rectangle(0, 0, rectSize, rectSize); // write Byte stream to destination rectangle cr.getBmd.setPixels (destRect, bytes); // pass the CustomRectangle to the final create method createFragmentParticle (xPos, yPos, cr); } |
The final function now creates from tile-Sprites single ParticleObjects and saves them to an Array. The method randRange() returns a random number wich makes the movement more dynamically…and oh yea, feel free to play with these parameters :)
// Create a fragment particle an push it onto the array private function createFragmentParticle (xPos:int, yPos:int, rect:BitmapDataRectangle):void { // create the fragment rectangle particle = new ParticleObject( container, rect as Sprite, xPos, yPos); // -> Play with these Parameters! // define velocity particle.setVel ( randRange(-20,20), randRange(-50,50) ); // add drag particle.drag = 0.97; // set gravity particle.gravity = 0.3; // randomize particle size particle.clip.scaleX = particle.clip.scaleY = 1.0; // set shrink particle.shrink = randRange (0.5,1.03); // add fade particle.fade = 0.01; // particle clip starting alpha particle.clip.alpha = 1.0; // -> ok stop // push particle onto Array partArray.push (particle); } // Calc a random range of particle movement private function randRange (min:Number, max:Number):Number { // e.g.: 5 - (-5) = 10; 10 + (-5) var randNum:Number = (Math.random() * (max - min )) + min; return randNum; } |
So far now the production of the FragmentationLayers is final. The call (here by a MouseClick Event on the container in the DocumentClass) of startEffect () bring the animation to run:
// Start the fragmentation effect public function startEffect ():void { this.addEventListener (Event.ENTER_FRAME, frameLoop); } |
This throws, as far as the variable dispEvent = true, a Custom-Event if the effect animation has finished and it always stops the EnterFrame Event:
// Effect has finished private function effectEnd():void { this.removeEventListener (Event.ENTER_FRAME, frameLoop); if (dispEvent) dispatchEvent(new Event(EFFECT_DONE, true)); } |
We catch the Custom-Event in the DocumentClass and repeat the fragmentation of the two loaded pictures:
overlay.addEventListener (FragmentLayer.EFFECT_DONE, effectDoneHandler); // FragmentLayer Effect Finished private function effectDoneHandler (e:Event):void { switch (e.currentTarget.name) { case "Overlay #1" : trace ("Effect done: " + e.currentTarget.name); // ...and again... init(); break; case "Overlay #2" : trace ("Effect done: " + e.currentTarget.name); break; } } |
The actual update of the ParticleObjects assumes frameLoop () in the FragmentLayer.as, which the above-mentioned startEffect() function releases.
// Effect frame-loop private function frameLoop (event:Event):void { // increasing part of the array which has to be updated part2update += updateRate; // ...if this part is too long, correct it if (part2update > partArray.length) { part2update = partArray.length; } // loop through Array and update each one for (var i:uint = 0; i < part2update; i++) { partArray[i].update (); // remove invisible particle if (partArray[i].invisible == true) { removeParticle (i); part2update --; i--; } } } |
We get rid of objects that have became invisible by removeParticle (). That method finally calls the effectEnd() function described above:
// Destroy a particle private function removeParticle (val:uint):void { var buffer:Array = partArray.splice (val, 1); particle = buffer.pop(); particle.destroy (); if (partArray.length < 1) { effectEnd(); } } |
Have fun trying it out!!




2009/01/14