search

Build a Custom Timer and Progress Meter in AS3

During this tutorial I will demonstrate how to make a custom timer which supports counting up or down to a specified amount of time.


Final Result Preview

In the demo below you will see the time counting down from 1:00, a progress bar that tracks the progress of the timer and a cancel button.

Once the countdown from the 1:00 is finished, or you press the cancel button, a Movie Clip slides in from the right. This Movie Clip lets you enter a desired time, and determines whether you have the time counting up or down. A progress bar will then be attached and will track the progress of the time. Once the time completes, or you press the cancel button, you will be able to enter a new time.


Step 1: Coding the Custom Timer Class

Here we will write the custom timer class that will drive our main movie.

Go to File > New and Choose Actionscript 3.0 Class. Save this file as “CountTimer.as”.

Flash AS3 countdown timer stopwatch

Step 2: Import Classes

Here we open the package and import the classes that we will need to write this class.

Add the following to the “CountTimer.as”


package
{
	//Needed for the Timer
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	//We will update this TextField with the time
	import flash.text.TextField;

Step 3: Variables and Constructor Function

Here we will declare the variables the class will need, and code the constructor function.

Add the following to the “CountTimer.as”.

public class CountTimer extends Timer
{
	//The textfield where the updated time goes
	private var targetText:TextField;
	//The direction of the timer i.e "up" or "down"
	private var direction:String;
	//How many minutes the timer has
	private var minutes:int;
	//How many seconds the timer has
	private var seconds:int;
	//Used in our calculation to update the timer
	private var totalSeconds:int;
	//The total amount of time = (Minutes+Seconds)
	private var timeTotal;
	//How much of the time has Passed
	private var timeLoaded = 0;
	//Set to true to test the timer
	private var test:Boolean = false;

	public function CountTimer(min:int,sec:int,dir:String,targetTextField:TextField=null)
	{
		minutes = int(min * 60);
		seconds = int(sec);
		timeTotal = minutes + seconds;
		super(1000,timeTotal);
		if (dir == "down")
		{
			totalSeconds = minutes + seconds;
		}
		else
		{
			totalSeconds = 0;
		}
		if (targetTextField != null)
		{
			targetText = targetTextField;
		}
		direction = dir;
	}

Here we declared some variables we need for our class.

The Constructor Function takes four parameters; they are as follows:

  • min: An integer value that represents how many minutes you wish the timer to have.
  • sec: An integer value that represents how many seconds you wish the timer to have.
  • dir: A string representing the direction of the counter can be one of the following: “up” or “down”.
  • targetTextField: A TextField that will be used to show the updated time (This is optional).

Inside the constructor function we set the minutes variable equal to the specified value of min * 60 (since 1 minute is equal to 60 seconds).

We then set the seconds variable equal to the sec.

Next we set the timeTotal variable equal to minutes + seconds.

Then we call super() — which run the code from the constructor function of the Timer class — pass in 1000 milliseconds, and the timeTotal variable. By using 1000 milliseconds we tell the timer to tick one time each second, and by passing in timeTotal we tell the timer how many times to fire.

We next check whether the dir parameter is equal to “up” or “down” and set the totalSeconds variable accordingly.The total seconds will be used in our timeHandler() function. We will increment or decrement this by 1 each timer the timer fires off.

Then we check whether or not the user has passed in a TextField to the constructor and set the targetText variable if they did; this will be used to display the time.

Finally we set the direction variable to the direction the user passed in.


Step 4: Coding the start() Function

Here we code the start() function for our timer.

Add the following the the to the “CountTimer.as”.

override public function start():void
{
	super.start();
	addEventListener(TimerEvent.TIMER, timerHandler);
}

Because we extended Timer we are overriding the Timer’s existing start() method. Here we simply call super.start() (which runs the code from the Timer class’s start() method) and add an EventListener to detect when the timer ticks.


Step 5: Coding the timerHandler Function

Here we code our timerHandler() function. This is where we update our time and display it. This function is called once every second.

Add the following to the CountTimer class.

private function timerHandler(e:TimerEvent):void
{
	//Update our time Loaded variable
	timeLoaded +=  1;

	if (direction == "up")
	{
		//totalSeconds is = 0, to start with. We add 1 to it.
		totalSeconds++;
	}
	else
	{
		//totalSeconds = theNumber of seconds by adding min and sec; we subtract 1 from it
		totalSeconds--;
	}

	//How may seconds there are left.
	seconds = totalSeconds % 60;
	//How many minutes are left
	minutes = Math.floor(totalSeconds / 60);
	//The minutes and seconds to display in the TextField.
	var minutesDisplay:String = (minutes < 10) ? "0" + minutes.toString() : minutes.toString();
	var secondsDisplay:String = (seconds < 10) ? "0" + seconds.toString(): seconds.toString();
	if (targetText != null)
	{
		targetText.text = minutesDisplay + ":" + secondsDisplay;
	}
	if (test=true)
	{
		trace(minutesDisplay + ":" + secondsDisplay);
	}
}

Inside this function we update our timeLoaded variable, which is used to track the progress of how much time has passed.

Next we check whether direction is equal to “up” or “down” and adjust our totalSeconds variable accordingly.

We next determine how many seconds and minutes are left; pad the minutesDisplay and secondsDisplay with an extra zero if necessary; update the TextField (if one was passed into the constructor); and optionally trace out the time if we’ve set our test variable to true (handy for testing if you don’t set a TextField).

The calculation used to determine the seconds variable takes the remainder of totalSeconds/60.The % (modulo) operator gives us the remainder.

The calculation used to determine the minutes variable simply takes the totalSeconds/60, rounded down using Math.floor().


Step 6: Coding the getTimeTotal() Function

Here we code a function that simply returns our timeTotal variable.Because we made this variable private we need a way to access it.

public function getTimeTotal():int
{
	return timeTotal;
}

Step 7: Coding the getTimeLoaded() Function

Here we code a function that returns our timeLoaded function. Once again because it is private we need a way to access it.

public function getTimeTotal():int
{
	return timeTotal;
}

Step 8: Coding the getProg() Function

This function gives us the progress of our time.It is how much of the total time (that we set in the constructor) has passed. We multiply by 100 so we get a percentage between 1 and 100.

public function getProg():int
{
	return Math.floor(timeLoaded/timeTotal*100);
}

Step 9: Testing the CountTimer Class

Here we begin to design the main movie that uses our “CountTimer” class.

Go to File > New and create a new ActionScript 3.0 document.

Flash AS3 countdown timer stopwatch

Set the size to 320x220px.

Save this document as “Timer.fla”. Go to File > New and choose Actionscript 3.0 Class.

Flash AS3 countdown timer stopwatch

Save this file as “Main.as”. We are going to test our CountTimer class,so add the following to the “Main.as”.

package
{
	import flash.display.MovieClip;
	import CountTimer;
	public class Main extends MovieClip{
	var countTimer:CountTimer;
	public function Main()
	{
		countTimer = new CountTimer(1,30,"up");
		countTimer.start();
	}

  }

}

Make sure you set the test variable in “CountTimer.as” to true, and set the movie’s Document Class to “Main”.

Press ctrl-enter and test the movie; you should see the time traced in the Output window.


Step 10: Designing the User Interface

Here we begin to design the main movie that uses our CountTimer class.

We will be using TweenLite in our movie so if you don’t have a copy get it from greensock.com.


Countdown/Countup Text

Select the Text tool and make sure the following properties are set in the “CHARACTER” Panel.

  • Size: 50.0 pt
  • Color: Black
Flash AS3 countdown timer stopwatch

Still in the “Character” panel, click on “Embed” and make sure “UpperCase”,”LowerCase”,”Numerals” are selected, and under “Also include these characters”
that you have added a “:” and a “%”.

Flash AS3 countdown timer stopwatch

Draw a textfield out on the stage and set the following properties under the “POSITION and SIZE” Panel.

  • X: 0
  • Y: 0
  • W: 320
  • H: 60
Flash AS3 countdown timer stopwatch

Give this TextField the instance name “timer_txt”; make sure the type is set to “Classic Text” and “Dynamic Text” respectively.

Flash AS3 countdown timer stopwatch

This TextField will be used to show the time when the movie first Starts.


Progress Bar

Now we need to design our progress bar.

Go to Insert > New Symbol. Give it the name “ProgressContainer” and make sure “Export for Actionscript” is checked and that the Class is set to “ProgressContainer”.

Flash AS3 countdown timer stopwatch

Go to Window > Components and drag a ProgressBar component into the movie clip.

Flash AS3 countdown timer stopwatch

Set the ProgressBar’s properties to the following.

  • X: 0
  • Y: 0
  • W: 320
  • H: 42.0

Under “Component Parameters” set mode to “manual”.

Flash AS3 countdown timer stopwatch

Give the ProgressBar the instance name “pb”.

Select the Text tool and make sure the following properties under the “CHARACTER” Panel are set.

  • Size: 30pt
  • Color: black

Draw a TextField into the movie clip.

Set the following properties on the TextField.

  • X: 80.0
  • Y: 1.0
  • W: 159.0
  • H: 38:0

Give this TextField the instance name “progress_txt”.

You can now close this MovieClip.


Growing and Fading Text

Now we will design the growing and fading text, to be displayed when all the time has elapsed.

Go to Insert > New Symbol.Give it the name “GrowFadeText” and make sure “Export for Actionscript” is checked and the Class is set to “GrowFadeText”.

Select the Text tool and make sure following properties are set under the “Character” Panel.

  • Size: 15pt
  • Color: [I set it to a blue, you can do the same if you wish]

Drag out a TextField into the MovieClip and set the following properties.

  • X: -69.0
  • Y: -6.35
  • W: 135.0
  • H: 21.0

Enter the text “TIMER COMPLETE” into the textField. You can now close this MovieClip.


Entry Fields

Now we will design the MovieClip that slides in from the left. Select the rectangle tool and set the color to white. Drag out a rectangle from the top left of the stage to the bottom right.

Select the rectangle you just dragged out and press F8.Give it the name “countContainer”.Make sure “Export for Actionscript is checked and that Class is set to “countContainer”.

Flash AS3 countdown timer stopwatch

Set the following properties on the MovieClip.

  • X: 322
  • Y: 0
  • W: 320
  • H: 220

Now double click to go inside the MovieClip.

Select the Text tool and make sure the following properties are set in the “CHARACTER” Panel.

  • Size: 50pt
  • Color: Black

Drag out a textfield onto the stage and set the following properties on it.

  • X: 0
  • Y: 0
  • W: 320
  • H: 60

Give this TextField the instance name “timer_txt” and make sure the type is set to “Classic Text” and “Input Text” respectively.

Once again select the Text tool and drag a TextField onto the stage.Then set the following properties on it.

  • X: 0
  • Y: 59.0
  • W: 320
  • H: 60

Give this TextField the instance name “instructions_txt” and make sure the type is set to “Classic Text” and “Input Text” respectively.

Go to Window > Components and drag three buttons inside this MovieClip.

Flash AS3 countdown timer stopwatch

Give the first button the instance name “countDown_btn” and set the following properties on it.

  • X: 14.00
  • Y: 160
Flash AS3 countdown timer stopwatch

Give the second button the instance name “cancel_btn” and set the following properties on it.

  • X: 103.00
  • Y: 160.00

Give the third button the instance name “countUp_btn” and set the following properties on it.

  • X: 182.00
  • Y: 160.00

You can now close the MovieClip.

Now that we have our UI Designed we can write the code for the main movie.


Step 11: Coding the Main Movie

If you are following along delete all the ActionScript in “Main.as” that you created in Step 9. That was for testing; now we need code that will work with our new interface.

Here we open the package declaration and import the classes we will be using.

Add the following to “Main.as”.

package
{
	import flash.display.MovieClip;
	import fl.controls.Button;
	import flash.text.TextField;
	import flash.events.TimerEvent;
	import flash.events.MouseEvent;
	import flash.text.TextFieldType;
	import flash.text.TextFieldAutoSize;
	import CountTimer;
	import com.greensock.TweenLite;
	import flash.events.Event;
	import fl.controls.ProgressBar;

Step 12: Variables and Constructor Function

Here we declare our variables and code the Constructor.

Add the following the the “Main.as”

public class Main extends MovieClip
{
	//An array to hold the minutes and seconds in elements [0] and [1]
	private var timeArray:Array;
	//Our countTimer
	private var countTimer:CountTimer;
	//A boolean that tells us whether this is the first timer
	//(the one used when the movie first starts)
	private var firstTimer:Boolean = true;
	//Direction of our timer can be "up" or "down"
	private var direction:String;
	//The MovieClip that contains the text we grow and fade
	private var growFadeText:GrowFadeText;
	//The MovieClip that holds our progressBar
	private var progressContainer:ProgressContainer;
	//The minutes
	private var min:int;
	//The second
	private var sec:int;

	public function Main()
	{
		min = 1;
		sec = 0;
		countTimer = new CountTimer(min,sec,"down",timer_txt);
		timer_txt.text = "1:00";
		countTimer.addEventListener(TimerEvent.TIMER_COMPLETE,timerComplete);
		setupButtons();
		addProgressContainer(0,70,"down");
		countTimer.start();
		stage.addEventListener(Event.ENTER_FRAME,updateProgress);
		cancel_btn.addEventListener(MouseEvent.CLICK,moveContainer);
	}

First we set up the min and sec variables and pass them to the countTimer; we then set the direction to “down” and set the target TextField to timer_txt.

We then set some default text for the TextField,add an TIMER_COMPLETE event to the Timer, run a function to set up our buttons,add the ProgressBar,start the Timer, and add an ENTER_FRAME event listener to the stage (which we’ll use to update the progress bar), and finally add a CLICK event listener to our cancel_btn.


Step 13: Coding the timerComplete() Function

Add the following to “Main.as”.

private function timerComplete(e:TimerEvent):void
{
	addGrowFadeText(154,130);

	if (firstTimer == true)
	{
		TweenLite.to(growFadeText, 2.5, {scaleX:2, scaleY:2,alpha:0,onComplete:moveContainer});
	}
	else
	{
		TweenLite.to(growFadeText, 2.5, {scaleX:2, scaleY:2,alpha:0,onComplete:showTheControls});
	}
}

Here we add the text to the stage by calling addGrowFadeText() we will examine this function shortly.We then check the firstTimer variable to see if this is the first timer, if it is use tweenLite to grow and fade the text and call the moveContainer function once the animation completes.If it not the first timer then we once again use tweenLite to grow and fade the text but call the showTheControls() function once the animation completes.We will examine the moveContainer and showTheControls functions shortly.


Step 14: Coding the setupButtons() Function

Add the following to “Main.as”

private function setupButtons():void
{
	countContainer.countDown_btn.addEventListener(MouseEvent.CLICK,doTimer);
	countContainer.countUp_btn.addEventListener(MouseEvent.CLICK,doTimer);
	countContainer.cancel_btn.addEventListener(MouseEvent.CLICK,restoreControls);
	countContainer.instructions_txt.text = "Enter time in format 1:30 then press CountDown or CountUp button";
	//We dont want user to be able to edit the text
	countContainer.instructions_txt.selectable = false;

}

Here we add some EventListeners to our Buttons, set the text for our instructions_txt and set it so the user cannot select or edit the text. I used a TextField here to keep this already long tutorial shorter, but you would probably want to use a Label component here and style it with a TextFormat Object.


Step 15: Coding the addProgressContainer() Function

Add the following to “Main.as”

private function addProgressContainer(xPos:int,yPos:int,dir:String):void
{
	progressContainer = new ProgressContainer();
	progressContainer.x = xPos;
	progressContainer.y = yPos;
	stage.addEventListener(Event.ENTER_FRAME,updateProgress);
	addChild(progressContainer);
	if (dir == "down"){
		progressContainer.pb.direction = "left";
	} else {
		progressContainer.pb.direction = "right";
	}
}

Here we create a new progressContainer and set its x and y properties by the xPos and yPos parameters that are passed in.We then add an ENTER_FRAME event listener that calls the updateProgress() function, and we add the progressContainer to the stage.Finally we check the dir parameter to see if it is equal to “down”; if it is we set the ProgressBar’s direction to “left”, otherwise we set the ProgressBar’s direction to “right”.


Step 16: Coding the removeProgressContainer() Function

Add the following to “Main.as”

private function removeProgressContainer():void
{
	if (progressContainer != null)
	{
		stage.removeEventListener(Event.ENTER_FRAME,updateProgress);
		removeChild(progressContainer);
		progressContainer = null;
	}
}

Here we check whether the progressContainer exists; if it doesn’t, then we remove the ENTER_FRAME event listener from the stage so it does not continue to run.We then remove the progressContainer from the stage and set it to null since we are done with it.


Step 17: Coding the updateProgress() Function

Add the following to “Main.as”.

private function updateProgress(e:Event):void
{
	progressContainer.progress_txt.text = countTimer.getProg().toString() + "%";
	progressContainer.pb.setProgress(countTimer.getTimeLoaded(),countTimer.getTimeTotal());
}

Here we set the progress_txt‘s text to show the progress of our timer.We use the countTimer’s getProg() method which returns an integer of what percentage of the time has passed.Since it returns an int we use AS3′s built in toString() method on it,and append a “%” sign to it.

Next we call the setProgress() method of the ProgressBar component on our ProgressBar (pb). We pass in countTimer.getTimeLoaded() and countTimer.getTimeTotal() which return integers. To learn more about the ProgressBar component check out my Quick Introduction to the ProgressBar component.


Step 18: Coding the addGrowFadeText() Function

Add the following to “Main.as”.

private function addGrowFadeText(xPos:int,yPos:int)
{
	growFadeText = new GrowFadeText();
	growFadeText.x = xPos;
	growFadeText.y = yPos;
	addChild(growFadeText);
}

Here we create a new instance of GrowFadeText, set its x and y properties as specified, and then we add it to the stage.


Step 19: Coding the removeGrowFadeText() Function

Add the following to “Main.as”.

private function removeGrowFadeText():void
{
	if (growFadeText != null)
	{
		removeChild(growFadeText);
		growFadeText = null;
	}
}

Here we check to see whether growFadeText exists. If it doesn’t, we remove it from the stage and set it to null.


Step 20: Coding the moveContainer() Function

Add the folowing to “Main.as”.

private function moveContainer(e:Event=null):void
{
	countTimer.stop();
	removeChild(timer_txt);
	removeChild(cancel_btn);
	removeGrowFadeText();
	removeProgressContainer();
	countContainer.cancel_btn.visible = false;
	firstTimer = false;
	TweenLite.to(countContainer, 1, {x:0});
}

Here we stop the timer and remove the timer_txt and cancel_btn. Next we call our removeGrowFadeText() and removeProgressContainer() functions, set the cancel_btn within the countContainer to be invisible, set the firstTimer variable to false, and slide the countContainer in using TweenLite.


Step 21: Coding the showControls() Function

Add the following to “Main.as”:

private function showTheControls():void
{
	showControls();
	removeProgressContainer();
	countTimer.stop();
	countContainer.timer_txt.text = "";
	countContainer.timer_txt.text = "";
}

Here we call the showControls function, which we will examine shortly. Next we call removeProgressContainer(), stop the timer and reset our TextFields to be blank.


Step 22: Coding the doTimer() Function

Add the following to “Main.as”:

private function doTimer(e:MouseEvent):void
{
	if (e.target == countContainer.countDown_btn)
	{
		direction = "down";
	}
	else
	{
		direction = "up";
	}
	if (countContainer.timer_txt.text != "")
	{
		timeArray = countContainer.timer_txt.text.split(":");
		min = timeArray[0];
		sec = timeArray[1];
		countTimer = new CountTimer(min,sec,direction,countContainer.timer_txt);
		countTimer.start();
		countTimer.addEventListener(TimerEvent.TIMER_COMPLETE,timerComplete);
		countTimer.addEventListener(TimerEvent.TIMER,updateProgress);
		hideControls();
		addProgressContainer(0,70,direction);
	}
}

We first check to see which button was pressed.If the countDown_btn was pressed we set the direction variable to “down” otherwise the we set the direction variable to “up”.Next we check to make sure timer_txt is not blank.If it is not then we use the split() function to put the minutes and seconds into the timeArray.The split() function takes a string and separates it by whatever you pass it as a parameter — here we used the colon (:) — and then adds each “piece” to the array. So, if you passed in "1:45", then the array’s element [0] would be “1″; element [1] would be “45″.

We then set the sec and min variables.

Next we create a new instance of the countTimer and pass in the min,sec,dir,and the TextField to use.

We then add two TimerEvent listeners that call our timerComplete() and updateProgress() functions.

Finally we call the hideControls() function and add the progressContainer to the stage.


Step 23: Coding the showControls() Function

Add the following to “Main.as”.

private function showControls():void
{
	countContainer.instructions_txt.visible = true;
	countContainer.countDown_btn.visible = true;
	countContainer.countUp_btn.visible = true;
	countContainer.cancel_btn.visible = false;
}

Here we simply set the instruction_txt,countDown_btn,and countUp_btn to be visible. We then set the cancel_btn to be invisible.


Step 24: Coding the hideControls() Function

Add the following to “Main.as”.

private function hideControls():void
{
	countContainer.instructions_txt.visible = false;
	countContainer.countDown_btn.visible = false;
	countContainer.countUp_btn.visible = false;
	countContainer.cancel_btn.visible = true;
}

This is the opposite of the previous function; here we just set the set the instruction_txt,countDown_btn,and countUp_btn to be invisible. We then set the cancel_btn to be visible.


Step 25: Coding the restoreControls() Function

Add the following to “Main.as”.

private function restoreControls(e:Event)
{
	showTheControls();
	countTimer.stop();
}

Here we call the showControls() function and stop the timer.


Step 26: Close the Class and Package.

Add the following to “Main.as”

	}//Close the Class

}//Close the Package

Here we close out our class and package.


Step 27: Set the Document Class and Test the Movie

Although not absolutely necessary,set the test variable to false in the “CountTimer”.as”.

Make sure your Document Class is set to “Main” and test the Movie.


Conclusion

We now have a versatile Timer Class that can be used for any number of things, from time limits on tests to setting times for levels on games.

I hope you found this tutorial useful and thanks for reading!



View full post on Activetuts+

Exclusive Freebie: Custom AS3 Slider

High time we featured another exclusive freebie on Activetuts+ eh? Well here’s a great little AS3 powered Slider, completely free for use in any project you like!


AS3 Custom Slider

Here’s the sider in its simplest form:

And here it is in action, altering the contSL (contrast) property of the AdjustColor class, updating a bitmap as it does so. Check out my previous tut on the ColorMatrixFilter class to learn more about how this is done.


Features

This Slider includes the following options:

  • Custom minimum range.
  • Custom maximum range.
  • Clean and good-looking skin.
  • Displays current value.

Usage

Drag the source MovieClip and the Main.as file to your project folder and edit the desired options.

package
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;

	public final class Main extends Sprite
	{
		public final function Main():void
		{
			addListeners();
		}

		private final function addListeners():void
		{
			slider.head.addEventListener(MouseEvent.MOUSE_DOWN, initDrag);
			slider.addEventListener(MouseEvent.MOUSE_UP, terminateDrag);
			stage.addEventListener(MouseEvent.MOUSE_UP, terminateDrag);
		}

		private final function initDrag(e:MouseEvent):void
		{
			slider.head.startDrag(false, new Rectangle(0, 0, slider.width - slider.head.width, 0));
			slider.addEventListener(MouseEvent.MOUSE_MOVE, onSliderMove);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onSliderMove);
		}

		private final function onSliderMove(e:MouseEvent):void
		{
			slider.head.txtTF.text = slider.head.x; //Use your custom range here
			slider.head.txt2TF.text = slider.head.x; //Use your custom range here

			/* Live Action here: this action will be updated as soon as you move the slider */
		}

		private final function terminateDrag(e:MouseEvent):void
		{
			slider.head.stopDrag();
			slider.removeEventListener(MouseEvent.MOUSE_MOVE, onSliderMove);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSliderMove);

			/* Action here: this action will be updated when the mouse button is released */
		}
	}
}



View full post on Activetuts+

Blow an Image Away with a Custom Wind Effect

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in March, 2010.

In this tutorial, we will create a custom class which breaks a picture into a thousand pieces and simulates a wind blowing them away. I created this project purely with AS3 and FlashDevelop – Flash not required!


Final Result Preview

Let’s take a look at the final result we will be working towards. Go ahead and click anywhere inside the SWF:


Quick Intro to FlashDevelop

FlashDevelop is a free code editor for Flash and Flex. You can use it to edit your class files when working with Flash software, or you can create an AS3 Project that doesn’t require Flash at all – and that’s exactly what we’ll be doing in this tutorial.

So download FlashDevelop and install it. Unfortunately, FlashDevelop only runs on Windows. Mac alternatives include FDT and Flex Builder, though neither are free. You can use Flash itself, and I’ll explain how to do this as we go along.


Step 1: Create a New Project

Open FlashDevelop and click Project>New Project…


Step 2: Set Up

Choose Actionscript 3 > AS3 Project. For the name of the Project put in “WindEffect.” For the location, click and navigate to the folder you would like to save it into. Leave the “Create Directory For Project” checkbox selected and click OK.

If you want to use Flash CS3/CS4, create a new Flash file and set the width and height of the stage to 550x250px, set the background color to black. Name it “windEffect.fla” and save it anywhere you like.


Step 3: Move the Source Image

For FlashDevelop, open the project directory and copy or drag windEffect.jpg from the source download (linked at the top of the page) into the \bin\ folder.

For Flash, copy or drag windEffect.jpg from the source download into the same folder where you have windEffect.fla.


Step 4: Install TweenLite

We’re going to use TweenLite by Greensock for the tweening. You can download the latest version of the component here; I’ve also included it in the source download.

For FlashDevelop, go ahead and copy or drag greensock.swc from the source download into the \lib\ folder for this project.

From FlashDevelop, click View>Project Manager


Step 5: External Library

Still in FlashDevelop, click the ‘+’ sign to the left of the lib folder to expand it. Right-click greensock.swc and select Add To Library.

For Flash, copy or drag the \com\ folder from the source download into the same folder as your windEffect.fla file.


Step 6: The Document Class

For FlashDevelop, open the project manager again (refer to Step 4), expand the \src\ folder and double-click Main.as. Below the imports and right above the class definition, add the following metadata tag to set up the stage properties:

[SWF (width = 550, height = 250, frameRate = 30, backgroundColor = 0)]

Within the init () method after the comment ‘entry point’, add the following code:

stage.scaleMode = StageScaleMode.NO_SCALE;	//don't stretch the stage
var effect:WindEffect = new WindEffect('windEffect.jpg');	//we will create the WindEffect class soon
addChild (effect);

That’s it for the Main document class.

For Flash, create a new Main.as class in the same folder as your project. Make sure the Main.as class is in the same folder as the fla. & com folder. Add the following lines:

package
{
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.events.Event;

	public class Main extends Sprite
	{

		public function Main():void
 		{
 			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
 		}

		private function init(e:Event = null):void
 		{
 			removeEventListener(Event.ADDED_TO_STAGE, init);
 			stage.scaleMode = StageScaleMode.NO_SCALE;	//don't stretch the stage

 			var effect:WindEffect = new WindEffect ('windEffect.jpg');	//we will create the WindEffect class soon
 			addChild (effect);
 		}
 	 }
}

Open Flash and assign “Main” as the Document class.

(Not sure what this is all about? Read this quick introduction to using a document class.)

If you try to run this now, you will get an error since we haven’t created the WindEffect class yet. Just make sure you save the file and leave it for now.


Step 7: Create the WindEffect Class

For FlashDevelop, click View>Project Manager, right-click the \src\ folder and choose Add>New Class.


Step 8: Setting Up the Class

Name the class WindEffect, click the browse button for the base class and enter flash.display.Sprite. Hit OK to complete.


Step 9: Importing Other Classes

Add all the necessary imports inside the package brackets right below ‘import flash.display.Sprite;’ and before the class definition. Click Save.

import com.greensock.easing.Strong;
import com.greensock.TweenLite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;

For Flash, create a new ActionScript file, name it “WindEffect.as” and save it in the same directory you have been using. It should be right next to the fla. file, com folder, and Main.as.

Add the following code:

package
{
	import com.greensock.easing.Strong;
	import com.greensock.TweenLite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;

	public class WindEffect extends Sprite
	{
		public function WindEffect ()
		{

		}

	}

}

Step 10: Add an Instance Variable

Add a private variable called “_pictureArray.” This is the only variable we will have in this class. Its main purpose is to hold references to all the small sprites that contain the little pieces of the picture once it’s been broken up.

Add the following line of code within the brackets
of the class:

public class WindEffect extends Sprite
{
	//this will house all the pieces of the picture we will animate.
	private var _pictureArray:Array;
}

Step 11: Add the Constructor

Add the following lines after the _pictureArray declaration:

public class WindEffect extends Sprite
{
	//this will house all the pieces of the picture we will animate.
	private var _pictureArray:Array;

	public function WindEffect ($url:String)
	{
		//we just call the load picture in the constructor
		loadPicture ($url);
	}
}

Step 12: Access the Image

Inside the loadPicture () method called by the constructor method, we instantiate a loader to load the windEffect.jpg. We also add a COMPLETE event listener to listen for when the load completes.

Add the following lines of code after the WindEffect () method. (Note that the parameter “$url” is the path to the picture we are loading passed from Main.as.)

private function loadPicture ($url:String):void
{
	//we create a loader with listeners to load the source picture we are using.
	//and then we load the image.
	var loader:Loader = new Loader;
	loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete);		//when it's loaded, call the onLoadComplete () function
	loader.load (new URLRequest ($url));
}

Step 13: Loading

After the image has been imported properly, this method is called. Add the following lines of code after the loadPicture () method and save the file.

private function onLoadComplete (e:Event):void
{
	//for testing
	addChild (e.target.content);
}

Step 14: Test One

Go ahead and hit CTRL + Enter on you keyboard. It should work and the image should be on the left top corner of the stage.

Now that we’ve checked it’s loading correctly, remove the addChild method and replace it with the following code:

createEffect (e.target.content);

Your WindEffect class should look something like this:

package
{
	import com.greensock.easing.Strong;
	import com.greensock.TweenLite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;

	[SWF (width = 550, height = 250, frameRate = 30, backgroundColor = 0)]

	public class WindEffect extends Sprite
	{
		private var _pictureArray:Array;

		public function WindEffect ($url:String)
		{
			loadPicture ($url);
		}
		private function loadPicture ($url:String):void
		{
			var loader:Loader = new Loader;
			loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete);
			loader.load (new URLRequest ($url));
		}

		private function onLoadComplete (e:Event):void
		{
			createEffect (e.target.content);
		}

	}

}

Step 15: Set up the Variables

The createEffect () Method will take the image parameter which is essentially a bitmap and break it down to 1250 pieces.

First we calculate the x- and y-positions to center the image on the stage. We save them into local variables called centerWidth and centerHeight.

Since the size of the image we are using is 300×100, I decided to divide the image 50 times horizontally and 25 times vertically. These values gave a pretty decent result with optimum performance. We save them in local variables, which I named “numberOfColumns” and “numberOfRows.”

We save the result of dividing the image’s width by numberOfColumns into “sizeWidth” and the result of dividing the image’s height by numberOfRows into “sizeHeight.”

The “numberOfBoxes” variable holds numberOfColumns multiplied by numberOfRows.

Next we instantiate _pictureArray so we can start putting small sprites into it. Add the following lines of code after the onLoadComplete () method:

private function createEffect ($bitmap:Bitmap):void
{
	//center the image horizontally.
	var centerWidth:Number = (stage.stageWidth - $bitmap.width) * .5;

	//center the image vertically.
	var centerHeight:Number = (stage.stageHeight - $bitmap.height) * .5;

	var numberOfColumns:uint = 50;
	var numberOfRows:uint = 25;
	var sizeWidth:uint = $bitmap.width / numberOfColumns;
	var sizeHeight:uint = $bitmap.height / numberOfRows;
	var numberOfBoxes:uint = numberOfColumns * numberOfRows;
	_pictureArray = [];

}

Step 16: Nested Loops

After instantiating _pictureArray we will add two loops, one inside the other. The first loop will handle moving on the x-position and will loop through all the columns, while the second loop will move on the y-position and will loop through all the rows.

Add the following lines of code inside the createEffect () method right after instantiating _pictureArray, then save the file:

for (var i:uint = 0; i < numberOfColumns; i++)
{
	//these loops are what splits the image into 1250 pieces.
	for (var j:uint = 0; j < numberOfRows; j++)
	{
		//let's see what it does.
		trace ('i:' + i, 'j:' + j);
	}
}

Step 17: Test Two

Test the movie by hitting CTRL + Enter.

As you can see, for every i there is a full loop of j. This is called “nesting loops”. This means that i which represents the x axis stays on one value while the second loop iterates for the y axis.

Put simply, we start with x=0, y=0; then the next iteration is x=0, y=1; then x=0, y=2, and so on.

When y reaches the end, the first loop increments by 1 and then again goes through the 2nd loop: x=1, y=0; x=1, y=1, x=1, y=2, etc. This goes on until the 1st loop completes.

You’ll see what this does when we apply it to some bitmap manipulation in the next few lines.


Step 18: Splitting the Image

From within the second loop, go ahead and remove the trace function we used for testing. Every time we loop we need to create a small picture having the width of “sizeWidth” and the height of “sizeHeight.”

This small picture will take a snap shot of a small part of the image starting from the top-left corner and moving through to the bottom-right. The “tempBitmapData” is where we will draw the small portion of the image. The “sourceRect” is the rectangle we will use to specify which part of the image will be copied.

Add the following lines inside the 2nd loop and save the file:

//1 temporary bitmapdata
var tempBitmapData:BitmapData = new BitmapData (sizeWidth, sizeHeight);

//1 temporary rectangle (x,y,width,height)
//we pass i * sizeWidth for the x parameter  & i * sizeHeight for the y parameter
//and the sizeWidth & sizeHeight for the width and height parameters.
var sourceRect:Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight);
trace (sourceRect);//for testing

Step 19: Even More Testing

Test the movie. What it does now is create a rectangle that adjusts its x- and y-positions each iteration.

As you can see, the 1st example shows x=0, y=0 and the next is x=0, y=4. This is what what we use for boundaries of the snap shot taken from the source image. Remove the test function when you’re ready to move on.


Step 20: BitmapData.copyPixels()

We then use the BitmapData.copyPixels () method to copy a small piece of the image based on the sourceRect. The parameters for this method are the bitmap image to copy, the rectangle area to copy and the destination point to where we will copy it.

Add the following line of code below the sourceRect declaration.

tempBitmapData.copyPixels ($bitmap.bitmapData, sourceRect, new Point);

We then create one temporary Bitmap to house the BitmapData we just copied and one temporary Sprite to house that Bitmap.

Then we push a reference of each Sprite onto _pictureArray for access later. After this we add the Sprite to the stage with the same coordinate as where we copied it from, thus recreating the original image.

We then offset the image by centerWidth and centerHeight to center it correctly on the stage.

Add the following lines of code and, once again, save the file:

//we then create 1 temporary bitmap to house the bitmapdata we just copied.
var tempBitmap:Bitmap = new Bitmap (tempBitmapData);

//and 1 temporary sprite to house the bitmap to enable interactivity.
var tempSprite:Sprite = new Sprite;

//we just add each box inside it's own sprite to enable interactivity since bitmaps by themselves are not interactive.
tempSprite.addChild (tempBitmap);

//each sprite is added into the _pictureArray array for access later.
_pictureArray.push (tempSprite);

//then position each of them onto the stage.
//We add the center width & center height so image centers on the stage.
tempSprite.x = i * sizeWidth + centerWidth;
tempSprite.y = j * sizeHeight + centerHeight;
addChild (tempSprite);

Step 21: Test Three

Go ahead and test it again. You should see the image correctly laid out on the stage. It won’t even look like it’s been separated into 1250 pieces.

Right after the closing bracket of the second loop, before we close the method, add the following line of code:

stage.addEventListener (MouseEvent.CLICK, blowWind);

We add an event listener to the stage to listen for a MouseEvent.CLICK. This will trigger the animation by running the blowWind() function, which we’ll create in the next step.

Your WindEffect class should look something like this:

package
{
	import com.greensock.easing.Strong;
	import com.greensock.TweenLite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;

	public class WindEffect extends Sprite
	{
		private var _pictureArray:Array;

		public function WindEffect ($url:String)
		{
			loadPicture ($url);
		}
		private function loadPicture ($url:String):void
		{
			var loader:Loader = new Loader;
			loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onLoadComplete);
			loader.load (new URLRequest ($url));
		}

		private function onLoadComplete (e:Event):void
		{
			createEffect (e.target.content);
		}

		private function createEffect ($bitmap:Bitmap):void
		{
			var centerWidth:Number = (stage.stageWidth - $bitmap.width) * .5;
			var centerHeight:Number = (stage.stageHeight - $bitmap.height) * .5;

			var numberOfColumns:uint = 50;
			var numberOfRows:uint = 25;
			var sizeWidth:uint = $bitmap.width / numberOfColumns;
			var sizeHeight:uint = $bitmap.height / numberOfRows;
			var numberOfBoxes:uint = numberOfColumns * numberOfRows;
			_pictureArray = [];

			for (var i:uint = 0; i < numberOfColumns; i++)
			{
				for (var j:uint = 0; j < numberOfRows; j++)
				{
					var tempBitmapData:BitmapData = new BitmapData (sizeWidth, sizeHeight);

					var sourceRect:Rectangle = new Rectangle (i * sizeWidth, j * sizeHeight, sizeWidth, sizeHeight);

					tempBitmapData.copyPixels ($bitmap.bitmapData, sourceRect, new Point);
					var tempBitmap:Bitmap = new Bitmap (tempBitmapData);
					var tempSprite:Sprite = new Sprite;
					tempSprite.addChild (tempBitmap);
					_pictureArray.push (tempSprite);
					tempSprite.x = i * sizeWidth + centerWidth;
					tempSprite.y = j * sizeHeight + centerHeight;
					addChild (tempSprite);
				}
			}
			stage.addEventListener (MouseEvent.CLICK, blowWind);
		}
	}
}

Step 22: Creating the Wind Effect

Start off by removing the MouseEvent.CLICK event listener since we need it to happen only once. Add the following lines of code after the createEffect () method:

private function blowWind (e:MouseEvent):void
{
	stage.removeEventListener (MouseEvent.CLICK, blowWind);
}

We need to go through all the sprites we assigned into _pictureArray and animate them individually.

TweenLite is applied to animate all the pieces towards the right as if wind were blowing on them.

The parameters are: the target for the tween, the duration of the tween, a variable object that holds all the properties, along with the values you want to apply the tween to.

For example: TweenLite.to (target, duration, {x:100, y:100, rotation:30, ease:Strong.easeIn, onComplete:trace, onCompleteParams:['hello']}).

The above example’s last two parameters are used for when the tween finishes. The onComplete parameter calls the trace function and the onCompleteParams parameter sends an array containing the string ‘hello’ into the trace function.

Add the following lines of code right after the remove event listener:

for (var i:uint = 0; i < _pictureArray.length; i++)
{
	TweenLite.to (
	_pictureArray[i],
	getRandomInRange (.25, 2, false),
	{
		x: stage.stageWidth + 100,
		y:_pictureArray[i].y + getRandomInRange (-100, 100, false),//
		rotation: getRandomInRange (-90, 90),
		ease:Strong.easeIn,
		onComplete:removeSprite,
		onCompleteParams:[_pictureArray[i]]
	}
	);
}

In the actual implementation, when we call TweenLite from within the loop, we assign the target as _pictureArray[current iteration].

For the duration we assign a value for the length of the tween to a random time between .25 seconds and 2 seconds.

The variable object holds 5 properties:

  • x:stage.stageWidth + 100 which will animate the sprite’s x property.
  • y:_pictureArray[i].y + getRandomRange (-100,100,false) which will get the current sprite’s y position and add a random number between -100 and 100 to give the animation an expanding effect.
  • rotation:getRandomRange (-90,90) rotates the current sprite to anywhere between -90 and 90 degrees.
  • ease:Strong.easeIn which makes the tween start slowly and suddenly speed up.
  • onComplete:removeSprite which calls the removeSprite method once the tween has finished and the Sprite is off the screen.
  • onCompleteParams which sends the array [_pictureArray[current iteration]] as the parameter for removeSprite.

Step 23: removeSprite () Method

This method is called from TweenLite when the animation for a particular tween has finished. We just remove the Sprite from the display list so there’s no clutter. Add the following lines of code after the blowWind () method:

private function removeSprite ($sprite:Sprite):void
{
	removeChild ($sprite);
}

Step 24: getRandomInRange () Method

I’m sure you’re familiar with this one (if not, Carlos Yanez has written a Quick Tip on the subject.) My version has an option of returning either whole numbers (int, uint) or floats (fractions).

Add the following lines of code. If you’re using FlashDevelop, you can save it as a custom snippet so it’s easily added to any class/project. I have it declared as a public static method for full accessibility.

public static function getRandomInRange ($min:Number, $max:Number, $rounded:Boolean = true):Number
{
	if ($rounded) return Math.round (Math.random () * ($max - $min) + $min);
	else return Math.random () * ($max - $min) + $min;
}

That’s it! Run the movie. If there’s anything wrong, check your code against the WindEffect class I’ve included in the source download.


Conclusion

The key to creating cool effects is to learn and master both image manipulation and animation tweening classes like TweenLite. Please feel free to drop a note for any comments, concerns, or suggestions. Thanks for reading!



View full post on Activetuts+

Quick Tip: Custom Crosshair Cursor and Gunshot Sound

In this Quick Tip we will create a custom crosshair along with a gunshot sound. This could be the basis for a shoot-’em-up game. In this example, we place bullet holes on the stage at the point where you click.


Note: In spite of the new Native Cursor feature introduced in FP10.2 this old-school method is still a valid way of creating a custom cursor. It has the advantage of allowing you to use bigger graphics, plus it’ll work with older versions of Flash Player. We’ll take a look at Native Cursor’s in FP10.2 tomorrow :)


Brief Overview

In the SWF you’ll see a Start button. When you click this button, your mouse becomes a crosshair ready to do some damage. As you click around on the stage, a gunshot sound plays and a bullet hole graphic gets added to the stage at the point where you clicked with the mouse.


Step 1: Setting Up the Document

Open a new Flash Document and set the following properties

  • Document Size: 500x400px
  • Background Color:#FFFFFF

Step 2: Setting up the Game Elements

For the Start Button, I drew a rounded rectangle and placed some text with the word Start on it. I then converted the Button and Text to a MovieClip by drawing a selection around them and pressing F8. I gave the button the name startGame, and also used startGame as the Instance Name in the Properties panel. If the Properties panel is not showing for you, go to Menu->Window->Properties or just press CTRL+F3.

custom cursor movieclip as3 flash
custom cursor movieclip as3 flash

Included in the exercise files are two images: one is the crosshair graphic, and the other is the bullethole graphic. I imported these one at a time to the stage and converted them to a MovieClip by clicking on them and pressing F8. I gave them the instance names “BulletHole” and “CrossHair”, made sure the registration points were set to the center in both cases, and used the same name for the Class in the Linkage of each symbol. Below is an image of how I set up the BulletHole; it is the same for the CrossHair.

custom cursor movieclip as3 flash

For the sound, I imported it to the Library then right-clicked it and selected Properties. I then gave it the name GunShot and set the Linkage Class as GunShot as well.

custom cursor movieclip as3 flash

Now that we have all our game elements ready we can dive into the code.


Step 3: Set up the Package and Main Class

Here we set up our package and the Main Class for our game

First we import some classes we will need, then we set up our document class. This main class must extend either MovieClip or Sprite; here we extend MovieClip. We then declare some variables we will be using, and code our constructor function. The constructor function adds an Event Listener to the button, which is where we set up the rest of the game.

package  {
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.ui.Mouse;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    public class Main extends MovieClip {
        //The movie clips and Sound in the Library
        var crosshair:CrossHair = new CrossHair();
        var bullethole:BulletHole;
        var gunshot:GunShot = new GunShot();

        //Needed for the gunshot sound
        var soundChannel:SoundChannel = new SoundChannel;

        //Whether or not the user has clicked 1 time
        var firstShot = true;
	}

    public function Main() {
        //Show hand cursor when user mouses over the button
        startGame.buttonMode=true;
        startGame.addEventListener(MouseEvent.CLICK,startTheGame);
    }
}

Step 4: Coding the startTheGame() Function

The startTheGame() function is called when the user clicks on the button. This function removes the button from the stage, hides the Mouse,and adds the crosshair to the stage. We then add two Event Listeners to the stage.

private function startTheGame(e:MouseEvent):void{
    //Remove the button from the stage
    removeChild(startGame);
    //Hides the mouse
    Mouse.hide();
    //Adds the crosshair and sets its x and y properties
    //to the mouse's x and y coordinates
    addChild(crosshair);
    crosshair.x = mouseX;
    crosshair.y = mouseY;
    stage.addEventListener(MouseEvent.MOUSE_MOVE,moveCursor);
    stage.addEventListener(MouseEvent.CLICK,fireShot);
}

Step 5: Coding moveCursor() and fireShot()

The moveCursor() function is called whenever the user moves the mouse, due to the MOUSE_MOVE event listener we added to the stage. In this function we simply make sure the crosshair is at the same position as the Mouse by using mouseX and MouseY.

private function moveCursor(e:MouseEvent):void{
    //Makes sure the crosshair x and y is always
    //where the mouse's x and y is
     crosshair.x = mouseX;
     crosshair.y = mouseY;
}

The fireShot() function is called whenever the user clicks on the stage. We first check to see if this is the first time the user clicked; if it is not, then we play the gunshot sound and add the bulletHole to the same position on stage where the user clicked by using e.stageX ande.stageY. The event holds information about itself — you can see what it contains by using trace(e.toString()).

If we did not check if this was the first time, then when the user first clicked on the Start button it would add a crosshair and play the gunshot sound (we don’t want that).

		private function fireShot(e:MouseEvent):void{
			//If they have clicked once then we do this
			if(firstShot == false){
				//Plays the sound
				soundChannel = gunshot.play();
				//Creates a new bullethole and adds it to the
				//stage at the place where the user clicked
				bullethole = new BulletHole();
				addChild(bullethole);
				bullethole.x = e.stageX;
				bullethole.y = e.stageY;
				//We always want the crosshair on top so we swap the "Depths"
				//of the crosshair and bullet
				swapChildren(bullethole,crosshair);
			}
			firstShot = false;

		}
	}//Close the class

}//Close the package

Conclusion

This could be the basis for many shoot-’em-up type games.It would be very easy to spawn some enemies and then do a hitTestPoint() check with the mouse’s X an Y against the enemy’s display object.

I hope you have enjoyed this tutorial. Thanks for reading!



View full post on Activetuts+

Create Custom Filters Using the Pixel Bender Toolkit

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in September, 2009.

Hi, once again, my name is André and in this tutorial I’ll demonstrate how to create custom filters with the Pixel Bender Toolkit, then use them with Flash CS4 to output .pbj files.

* This feature works only in Flash Player 10.


Step 1: The Pixel Bender Toolkit

The Pixel Bender Toolkit comes with the Adobe Master Collection CS4 pack, or you can download it at http://labs.adobe.com/downloads/pixelbender.html.


Step 2: The Basics

Before creating any filter, we must understand the basic functions and types of the language. It’s different to Flash, and much simpler.

The input keyword: This is the input image, the image that will be read and worked on. We can have up to 2 input images in the code, working with one image will create a filter, and working with 2 images will create a blend mode. The input is always type of “image4″, which is an image in RGBA mode (Red, Green, Blue and Alpha).

The output keyword: This is the output pixel, as opposed to the input. This will not output the image, this will just output the pixel read in RGBA. This is type “pixel4″ (and not image4 like the input).

The parameter keyword: Parameter keyword will work like a setter function. With the parameter the values of the filter can be changed when in use. The parameter must be followed by the type and name, and can also have minimum value, maximum value and default value. Example: parameter int dimension <minValue:1; maxValue:10; defaultValue:1;>; or parameter float myfloat <minValue:1.0; maxValue: 2.0; defaultValue: 1.0>. Also the parameter can be typed float2, float3, float3, int1, int2… example: parameter float2 test <minValue:float2(1.0,2.0);maxValue:float2(5);defaultValue:float2(1.0,2.0);>;

Also we have the types float, float2, float3, float4, int, int2, int3, int4 and many others which we will not use here. Also, some types don’t work with Flash Player 10, so I won’t get into them right now. I will, however, discuss a little bit about the types I’ve mentioned here and how they work.

Type float, float2, float3 and float4: when you create a float4 type for example, you are creating an array of 4 float values. In Pixelbender the float values are define by dot, but float() also works like a function to convert other number values in float. For example "float4 test=float4(1,2,3,4);". Here we have an object with 4 values (type float) in “test” variable. You can also create a float4 object from one value, for example: "float4 test=float4(3);". Here we have an object with 4 values (RGBA) and all values are the same (3.0 float). When you create a float value, you can also create it using a dot like "float test=1.0;". If you try to define it like "float test=1;" it will throw an error, because numbers without a dot in pixelbender work like int values.

So float are always defined by dot. Even using “float()” to create the float value will return a number with a dot. Lastly, to access float values with more than one value you can use syntax like an array access ” variable[0] or variable[1] or variable[2] … “.

Type int, int2, int3 and in4 are the same thing as float types, but don’t have dots. You can also convert number values using “int” like functions.

evaluatePixel(): this function runs over all the image, pixel by pixel, and then returns the output type pixel4. In custom filters for Flash we always use this function.

outCoord(): this function returns the current coordinate of the pixel being read by the evaluatePixel function. It returns a value type float2, x and y values, and can be accessed by [] like array or .x and .y like object. For example: var out=outCoord(); //out.x is the same of out[0] and out.y is the same of out[1].

sampleNearest(source,pixelCoordinate): this function returns the float4 value of the pixel from the source image (image4) at the coordinations “pixelCoordinate”. Normally we use the “outCoord” function here.

An observation must be made; when using float values and you want to add/subtract/multiply or divide the values with other float value of the same length, you can use them like this example:

  float4 test1=float4(3.0,2.0,2.0,3.0);
  float4 test2=float4(1.0,2.0,2.0,1.0);
  float4 result=test1-test2;

The result will be a variable type float4 with values 2.0, 0.0, 0.0 and 2.0. Also, you could use:

  float4 test1=float4(3.0,2.0,2.0,3.0);
  float4 test2=float4(1.0,2.0,2.0,1.0);
  float4 result=test1;
  result[0]=test1[0]-test2[0];
  result[2]-=0.5;

I think this is enough to understand the structure of Pixel Bender code, let’s move onto the next step, after I’ve mentioned just one more thing:

Before testing any filter, it’s important to load at least one image (file > load image 1″). To test the filter you can go to build > run, if the filter has any parameters, on the right side of the application you’ll see sliders to change the values. They change at runtime and have a live preview, since each time you press run again.


Step 3: Create a New Pixel Bender Filter

This filter comes with Pixel Bender Toolkit, but is one of the simpler filters to explain. For more about the Pixel Bender language reference just hit F1 button in the program, and the help in .pdf will open.

Once the program is open, create a new Kernel Filter (file > new kernel filter) the program will create a default structure for the filter:

<languageVersion : 1.0;>
kernel NewFilter
<   namespace : "Your Namespace";
    vendor : "Your Vendor";
    version : 1;
    description : "your description";
>
{
    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        dst = sampleNearest(src,outCoord());
    }
}

In kernel NewFilter, you change the name NewFilter for the name of your filter. Namespace, vendor, version and description I don’t need to explain, just your strings like author, version (int) and the description.

The input image will be the image loaded by the filter and the output will be the pixel generated by the evaluatePixel function. The output will be a pixel4 value generated by the evaluatePixel function, which runs pixel by pixel of the input image as I’ve explained.

At the line “dst = sampleNearest(src,outCoord());” we are getting the value of the current pixel, and the coordinate outCoord() from image src (the input image), so we can modify the values of the rgba value of the dst. For example, if we want to invert the colours of the input image, we could do the following:

    dst = sampleNearest(src,outCoord());
    dst.rgb=float3(1)-dst.rgb;

What are we doing here?

We are stating that the rgb value of this pixel is the array of float3 value less the original value of rgb, so the color will be inverted. You can use the dst.rgb instead of using dst[0], dst[1]… and the order after the dot can be any order, it will read each letter as the value of the color. For example, you can use dst.gbr=float3(1)-dst.gbr. Another thing you can try is to change the colours of the image. For example by using the code below (inside the evaluatePixel function):

    dst = sampleNearest(src,outCoord());
    dst.rgb=dst.brg;

This code will output an oddly coloured image.


Step 4: Testing a Prepared Code From Adobe

Let’s test a filter from Adobe. The pixelate filter is great for testing, so go to file > open; in the folder where Pixel Bender is installed there are some filters. Let’s choose the pixelate filter. Once it’s open you can hit the “run” button to test the filter. If you want to export, go to file > Export kernel filter for flash player. This will export the filter to use with Flash, you can load the filter with the URLLoader or embed with the Embed tag from Flex SDK. In this tutorial I will show how to work with the embedded file, since the filter weighs only about 4kb to 15kb (it’s very lightweight).

The output extension is a .pbj file.


Step 5: Create the Folder Structure

If you have a classpath for Flash, use your classpath, if you dont have one and want to create one, open my previous tutorial and follow Step 1. If you don’t want a classpath, use the same folder of your .fla document. Let’s assume the classpath for the tutorial.

In your classpath create the folder “pixelbender”. Then inside the “pixelbender” folder, inside your classpath create the folder “pbj”. Copy the .pbj file (example: pixelate.pbj) to this pbj folder you’ve created.


Step 6: Creating the Class for the Pixelate Filter

Open Flash CS4, or Flex with updated SDK for FP10. If you’re using Flash, it’s important to setup the Flex SDK for Flash. If you don’t know how to do this, hit “ctrl+u” to open the preferences of Flash, then select the “actionscripts” at category, then “Actionsctipt 3.0 settings”. In the window “Actionscript 3.0 advanced settings” click the “+” button of the library path and add the following: $(FlexSDK)/frameworks/libs/flex.swc. Click the OK button.

Now create a new .as file, and start coding the following:

First we set the package and import the necessary classes.

package pixelbender{
	import flash.display.Shader;
	import flash.filters.ShaderFilter;
	import flash.utils.ByteArray;

Create the public class PixelateFilter extending the ShaderFilter. The ShaderFilter can be applied as a normal filter in the filter array of any DisplayObject.

public class PixelateFilter extends ShaderFilter{

Embed the pixelate.pbj file in the folder pbj (we’re assuming that we’ll save the .as in the pixelate folder of our classpath). The embed tag is a Flex tag which embeds files in a swf instead of loading them. There are lots of types that you can embed, like .flv, .jpg and others, and as mimeType application/octet-stream the file will be embedded as ByteArray. The embed tag creates a class for the embedded file, here I’m using a class named “Filter”.

[Embed(source="pbj/pixelate.pbj",mimeType="application/octet-stream")] private var Filter:Class;

In the constructor, let’s create an instance of our embedded file as ByteArray. The ByteArray is the Shader constructor’s parameter, so we’ll also create the shader instance, setting the filter to “ByteArray” as the parameter of the constructor. Since we’re extending the ShaderFilter, we don’t need to create an instance of the ShaderFilter. This class is already ShaderFilter extended, so all we need to do is set the shader parameter of our ShaderFilter class as the shader instance.

public function PixelateFilter():void
{
	var filter:ByteArray=new Filter() as ByteArray; //The embedded file as ByteArray
	var shader:Shader=new Shader(filter); //The instance of Shader
	this.shader=shader; //setting the parameter shader of our class
}

Now we create a new parameter for our class, the parameter “dimension”. This parameter will affect the “parameter int dimension” created in the pixelbender. The setter function will alter the value, and the getter function will just get the current value. The shader data values can be accessed by “instance.data.value”, the values are arrays. If we had a parameter “parameter int2 position;” in the filter for example, we would access it by “instance.data.position[0]” and “instance.data.position[1]” respectively.

public function set dimension(value:Number):void
{
	shader.data.dimension.value[0]=value;
}

public function get dimension():Number
{
	return shader.data.dimension.value[0];
}

After all that, just close the package and the class.

}
}

Now the class for this filter is created, save the .as file with the name “PixelateFilter.as” (the same name as the class) in the pixelbender folder inside your classpath (same name as your package, and where you’ve also created the pbj folder).


Step 7: Test the New Filter

First step, create a new .fla AS3 document, save it anywhere you want, for example c:/mycustomfilter.

Define a class for this .fla document. Open the properties panel of the .fla document from the window > properties, in the box “Class” type “Main”, and create a new actionscript file.

Copy any image to the same folder of the .fla document, for example I’ve used one of the sample images from the Pixel Bender examples; YellowFlowers.png, which can be found with the source files.

If you don’t have the TweenLite class yet, please download it at http://blog.greensock.com/tweenliteas3/, and unpack the contents of gs folder inside the gs folder in your classpath.

Create a new .as document.

Include the necessary classes to our classpath:

package{
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import pixelbender.PixelateFilter; //Our custom filter
	import gs.TweenLite; //the best Tweening class

Create the Main class extending the Sprite class:

public class Main extends Sprite{

Embed the image for testing, the mimeType is “image/png”, so we’re embedding as image not ByteArray. Name its class “Img”. Additionally, we type a variable named “filter” of the type PixelateFilter, so we can use it in any function later on.

[Embed(source="YellowFlowers.png",mimeType="image/png")] private var Img:Class;
private var filter:PixelateFilter;

In the constructor, we start creating our image, which will be affected by the filter, then add the image child to the stage. Then create instance of PixelateFilter. We’ve created the variable before, so we don’t need to type again. Set the filter dimension to 100, so we can see the effect better, also add the filter to the filterlist of our Main class.

Then using the TweenLite class we animate the filter parameter. The dimension parameter will be animated from 100 to 1. While the animation is being updated, the function “tweenLiteUpdate” is executed, and when it’s finished animating the “newTween” function will be executed.

public function Main():void{
	var image:Bitmap=new Img() as Bitmap;
	addChild(image);
	filter=new PixelateFilter();
	filter.dimension=100;
	this.filters=[filter];
	TweenLite.to(filter,3,{dimension:1,onUpdate:tweenLiteUpdate,onComplete:newTween});
}

While TweenLite is being updated, the tweenLiteUpdate is executed and updates the filter of our Main class. Without this method we wouldn’t see the TweenLite updating the filter.

private function tweenLiteUpdate():void{
	this.filters=[filter];
}

When the first Tweening animation completes, it will run the newTween function. The first line of this function will check if the filter dimension value is 1. If so, it will set the dim variable to 100, else it’ll set the variable to 1. This is the same with if and else, or switch. The second line will start the Tweening animation of the filter again.

private function newTween():void{
	var dim:Number=(filter.dimension==1)?100:1;
	TweenLite.to(filter,3,{dimension:dim,onUpdate:tweenLiteUpdate,onComplete:newTween});
}

Now just close the package and the class with double “}”.

}
}

Save your file as “Main.as” in the same folder of your .fla file, and if all files and folder are OK, you can test your file. The animation will start pixelated, changing to the normal image, and will loop continuously.


Conclusion

I hope you liked this, and I hope it will be very useful. In Adobe Exchange there are a lot of other filters you can download, some of them are free or open source. I’ve also put some other .pbj and classes with the source for studying. For example, SpherizeFilter.as: http://cavallari.freehostia.com/spherize/, animates by the position of the mouse.



View full post on Activetuts+

Page 1 of 41234
top