AS3: Fragmentation Class Tutorial Pt. 2

January 14th, 2009 // 3 Comments // Posted by Paul

Hello.

Deutsche Version

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:

AS3 Fragment Class thumbnail sketch

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!!

Download Sources

3 Comments to AS3: Fragmentation Class Tutorial Pt. 2

[...] english version [...]

Paul
2009/01/14

hmm… there is a little layout error i could not get rid of. It´s the HTML declaration of special characters e.g.:

if (partArray.length < 1)

should look like this:

if (partArray.length < 1)

and so on :(
Admin can you please provide an opportunity to fix this? thx

[...] English Version [...]

Leave a comment

This Blog is discontinued…

We're no long generating content for Cityclouds. Consider it an archive for great things we found on the web and elsewhere from 2008 to 2012. The future is bright anyhow...

Categories

Archive