Jan 20, 2012
Posted on Jan 20, 2012 in Hints and Tips | 10 comments
In the previous Quick Tips, we’ve looked at collision detection – essentially, detecting that two shapes have overlapped. Now, we’re ready to look at collision reaction: making something happen due to a collision. In this Quick Tip, we’ll look at the reactions of reflection and sliding.
Final Result Preview
Let’s look at the end result we’ll achieve at the end of this tutorial. Each Flash demo has a restart button; click it to reset the position of the circles at the top of stage.
The first demo shows off reflection:
The second shows sliding:
Step 1: The Reflection Formula
I’ve run through this topic several rounds with students, and experience has taught me that the head-on approach of explaining vector math to freshers results in blank faces and confused minds. So instead of putting up a Math lecture here, I shall refer those who are interested in investigating this topic further to Wolfram’s page on reflection.
Here, I shall simplify my explanations with diagrams below. Recall vector addition:
Now, observe the diagram below. A is the circle’s velocity before a collision, and A’ is its velocity after the collision.
It’s obvious that A' = A + 2 V(Ap), where V(Ap) represents the vector with a magnitude of Ap, in the direction of the left normal. (You can see this by following the dashed lines.)
In order to obtain V(Ap), we shall project A onto the left normal.
Step 2: Implementation
Here comes the ActionScript implementation of reflection. I’ve highlighted the important parts. Line 67 – 69 is to calculate V(Ap) (v_leftNormSeg2) and line 70 implements the formula. You may refer to the full Actionscript under Reaction1.as.
(You should recognise most of the code from the previous Quick Tip.)
private function refresh(e:Event):void {
for (var i:int = 0; i < circles.length; i++) {
//calculating line's perpendicular distance to ball
var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
var c1_circle_onLine:Number = c1_circle.projectionOn(line);
//if collision happened, undo movement
if (Math.abs(c1_circle_onNormal) <= circles[i].radius
&& line.dotProduct(c1_circle) > 0
&& c1_circle_onLine < line.getMagnitude()){
//redefine velocity
var v_leftNormSeg2:Vector2D = leftNormal.clone();
var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal))
v_leftNormSeg2.setMagnitude(leftNormSeg2_mag);
velos[i] = velos[i].add(v_leftNormSeg2.multiply(2));
}
circles[i].x += velos[i].x;
circles[i].y += velos[i].y;
}
}
Step 3: An Interactive Version
Take note that this reflection formula is applicable to line of any gradient. In fact, you can program your line to be adjustable at runtime and see it reflecting circles like the Flash presentation below. Just click and drag near the lower end of the to redefine it.
Step 4: Sliding Along Line
The concept of sliding along the line is almost identical to reflection. Observe the diagram below.
The vector of slide is A' = A + V(Ap) with V(Ap) representing a vector with magnitude of Ap. Again, to obtain Ap we shall project A onto the left normal.
Note that as the circle is sliding along the line, it is colliding with the line. Of course, collision points differ among circles that collide onto line, so some overlap the line as they move along it. This doesn’t look good, so we’ll have to reposition them.
Step 5: Redefine Location
Now, let’s reposition circles on the line while maintaining their contact with line. Refer to the diagram below.
An important variable to calculate is the projection of A along line. The radius of circle is readily available, and we already have B, so we can form the vectors of B and C. Adding the two will give us A, the exact location to reposition circle. Simple!
The Flash presentation below is coded according to the mentioned idea. But there is one problem: the circles jitter along the line.
There’s one final detail we missed. Diagram above shows magnitude of C should be equivalent to radius of circle. However, this will position circle back above the line. Since there’s no collision detected there, the circle will fall onto the line again, which in turn will flag the collision detection and cause the circle to be repositioned.
This cycle will repeat until the is past the end of the line segment; the visual result of this cycle is the jittering effect.
The solution to this problem is to set the magnitude of C to slightly less than the radius of the circle: (radius of circle - 1), say. Observe the Flash demo below which uses this idea:
Step 6: Implementation
So here’s the important ActionScript snippet for sliding along the line. I’ve highlighted the important parts.
private function refresh(e:Event):void {
for (var i:int = 0; i < circles.length; i++) {
//calculating line's perpendicular distance to ball
var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1);
var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal);
var c1_circle_onLine:Number = c1_circle.projectionOn(line);
//check for collision
if (Math.abs(c1_circle_onNormal) <= circles[i].radius){
//check if within segment
//if within segment, reposition and recalculate velocity
if (line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) {
//repostion circle
var v_lineSeg:Vector2D = line.clone();
v_lineSeg.setMagnitude(c1_circle_onLine);
var v_leftNormSeg1:Vector2D = leftNormal.clone();
v_leftNormSeg1.setMagnitude(circles[i].radius - 1);
//v_leftNormSeg1.setMagnitude(circles[i].radius); //uncomment this to check out the error: jittering effect
var reposition:Vector2D = v_lineSeg.add(v_leftNormSeg1)
circles[i].x = x1+reposition.x;
circles[i].y = y1+reposition.y;
//redefine velocity
var v_leftNormSeg2:Vector2D = leftNormal.clone();
var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal))
v_leftNormSeg2.setMagnitude(leftNormSeg2_mag);
var veloAlongLine:Vector2D = velos[i].add(v_leftNormSeg2);
circles[i].x += veloAlongLine.x;
circles[i].y += veloAlongLine.y;
}
//if not in segment (e.g. slide out of segment), continue to fall down
else {
circles[i].x += velos[i].x;
circles[i].y += velos[i].y;
}
}
//No collision in the first place, fall down
else {
circles[i].x += velos[i].x;
circles[i].y += velos[i].y;
}
}
}
Conclusion
Hope this is helpful. Thanks for reading. Prompt me if there are questions, and I’ll see you next Quick Tip.



View full post on Activetuts+
Jan 19, 2012
Posted on Jan 19, 2012 in Hints and Tips | 10 comments
In this tutorial I will introduce you to FZip, an AS3 Library that lets you open zip files inside your Flash projects. This can save a lot of bandwidth; in this tutorial we will load an 2.5MB zip file which contains 9.3MB worth of assets.
Final Result Preview
Let’s take a look at the final result we will be working towards. Click here to open a SWF that will in turn load a zip file full of images, and display them in a tiled grid.
(The blurring visible on some icons is due to Flash automatically attempting to scale them up to 32x32px, even though those particular images are 16x16px.)
Step 1: Getting the Library and Zip Archive
You will need to grad a copy of the FZip library from Claus Wahlers’ github.
Extract the library. Inside the src folder there is a folder named “deng”; copy this folder to the folder where you will store your FLA.
Next we need a zip archive to work with. I choose the WooFunction icon set, available for free from woothemes.com.
Save this to the same directory where you will store your FLA.
Step 2: Create New Flash Document
Open a new FLA and give it the following properties:
- Size: 550x400px
- Background Color: White
Save this as fzip.fla.
Step 3: Add Components to Stage
Go to Window > Components and drag a TileList component to the stage.
Under “Component Parameters” set the following properties:
columnCount: 16
columnWidth: 32
rowCount: 8
rowHeight:32
Give the TileList the instance name imageTileList, and set the following properties in the “Position and Size” panel:
- X: 20
- Y: 68
- W: 100
- H: 100
Next select the Text Tool and make sure the following properties are set in the “Character” panel:
Now drag a TextField onto the stage, and give it the instance name imagesLoaded. Make sure the TextField is set to “Classic Text” and “Dynamic Text”, respectively, and set the following properties:
- X: 54
- Y: 161
- W: 454
- H: 60
Step 4: Create new AS3 Document
Go to File > New and choose “Actionscript File”.
Save this file as Main.as.
Step 5: Package, Imports and Constructor
Inside Main.as add the following:
private function demonstrate():void
package {
import flash.display.MovieClip;
import deng.fzip.FZip;
import deng.fzip.FZipFile;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.*;
import fl.controls.TileList;
import fl.data.DataProvider;
public class Main extends MovieClip {
public function Main() {
setupZip();
}
}
}
Here we imported the classes we will need for this tutorial, and set up the Main() constructor function.
Step 6: Add Variables
Define the following variables above public function Main():
private var zip:FZip; // Instance of FZIP class
private var numFiles:int = 0; //Number of files
private var numFilesLoaded:int = 0; //Number of files loaded
private var done:Boolean = false; //Done processing zip archive?
private var tileListDp:DataProvider = new DataProvider();//Data provider for the TileList
Here we add some variables we will need throughout the tutorial. See the comments for their usage.
Step 7: setupZip()
Add the following new function below Main():
private function setupZip():void{
zip = new FZip();
zip.addEventListener(Event.OPEN, onOpen);
zip.addEventListener(Event.COMPLETE, onComplete);
zip.load(new URLRequest("wootheme.zip")); //change this to match your zip file's URL
imageTileList.visible = false;
}
Here we create a new instance of the FZip class, add two event listeners, and load our zip file. Last, we set imageTileList to be invisible (We don’t want it to show until all the images from the zip have loaded).
Step 8: onOpen()
Add the following new function beneath the setupFzip() function you entered above:
private function onOpen(evt:Event):void {
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
This function gets called when the zip archive has been opened. Here we add an ENTER_FRAME event listener.
Step 9: onComplete()
Add the following code new function beneath the onOpen() function you entered in the step above.
private function onComplete(evt:Event):void {
done = true;
}
This function gets called when there are no more files to process from the zip archive.
Step 10: onEnterFrame()
Add the following beneath the onComplete() function you entered above. This function will be triggered every frame after the zip file has been opened:
private function onEnterFrame(evt:Event):void {
//Only load 32 files per frame, to save processing power
for(var i:uint = 0; i < 32; i++) {
// any new files available?
if(zip.getFileCount() > numFiles) {
//yes so get it
var file:FZipFile = zip.getFileAt(numFiles);
// is this a png in the icons folder?
if(file.filename.indexOf("woofunction-icons") == 0 && file.filename.indexOf(".png") != -1) {
var loader:Loader = new Loader();
loader.loadBytes(file.content);
tileListDp.addItem({source:loader});
numFilesLoaded++;
}
numFiles++;
} else {
// no new files available
// check if we're done
if(done) {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
removeChild(imagesLoaded);
imageTileList.visible = true;
imageTileList.dataProvider = tileListDp;
}
//Exit the Loop
break;
}
}
imagesLoaded.text = numFilesLoaded + " Images Loaded";
}
Here’s the meat of the code.
Since this is running every frame, we’ll place an artificial restriction on the number of files within the archive that we deal with at once. That’s the purpose of the for-loop.
zip.getFileCount() reveals how many files are in the zip; numFiles stores how many files we’ve dealt with so far. So, line 5 checks whether there are still more files to deal with.
If there aren’t any files left, we skip to line 17 and just do some basic clearup: remove the ENTER_FRAME listener, remove the “loading” text field , make the tile list visible, and link it to the data.
If there are files left, we get the next one in our list using numFiles as an index. We then check whether it’s a PNG from the icons folder; since we know the structure of the zip beforehand, we can cheat and just check whether the file’s name and path contains “woofunction-icons” and “.png”.
To get the image from the zip and into a DisplayObject, we can use a Loader. This class is often used to load an image from a URL, but here we’re using its loadBytes() method to get the data from the ByteArray created by FZip.
Since Loader extends DisplayObject, we can just add it straight to the TileList’s DataProvider. Then we increment both numFilesLoaded and numFiles.
Why do we have two integers to keep track of how many files are loaded? Well, numFiles keeps count of all the files we’ve examined from the zip, whereas numFilesLoaded keeps count specifically of the image files that we’ve loaded into the DataProvider. It’s the latter variable that we use to update the “loading” text at the end of the function.
Conclusion
FZIP is an amazing little utility to save some loading time and bandwidth. I hope you’ve found this tutorial useful, and thanks for reading!



View full post on Activetuts+
Jan 18, 2012
Posted on Jan 18, 2012 in Hints and Tips | 10 comments
Building a button from a bitmap can be bothersome. If you’re using the Flash IDE, you can create a mask to determine which pixels are part of the button and which aren’t, but in any other workflow, the entire rectangle containing the bitmap – including any transparent pixels – will be clickable. In this tutorial, you’ll learn how to automatically make all transparent pixels unclickable, with just a few lines of code.
Final Result Preview
Let’s take a look at the final result we will be working towards:
Notice that the hand cursor only appears when hovering over the actual image; even the gaps in the hair don’t cause it to appear. And it’s not just for show: the button presses only register when clicking on these areas.
Introduction: What’s So Special?
At a first glance, the SWF above appears extremely simple. But look closer! Notice how in the demo above, a button press is only counted if you click somewhere on the actual image. This isn’t what would normally happen. Since a bitmap image is always a rectangle, clicking anywhere inside its rectangle normally would count as a button press. Take a look at the example below, where I have outlined the boundary rectangle of our image. Here, you can click anywhere inside the rectangle, including the transparent areas.
As you can see, this is not what we want! For starters, a user could accidentally click the button when he doesn’t mean to. In addition, it looks strange when a hand cursor appears over blank space. In this tutorial, you’ll learn how to easily correct these problems.
If you aren’t already familiar with Object-Oriented Programming or FlashDevelop, I recommend checking out the provided links before starting this tutorial.
Step 1: Getting Started
Open up FlashDevelop and create a new AS3 project (Project > New Project) and call it something like BitmapButtonProj. On the right, open up the src folder and double-click Main.as to open it. Add a new class to your project (right-click /src/ > Add > New Class) called BitmapButton
Step 2: Embedding an Image
We now need an image to work with. Here is the one I’m using:
To use a bitmap image (such as a .jpeg file or a .png file) in Actionscript 3, we have to embed it. FlashDevelop makes this easy. After saving the above image somewhere, right-click the lib folder on the right, mouse over Add, and select the Library Asset option.
If you want to use your own image, be sure to select one with transparency.
The image you selected will now appear in the lib folder in FlashDevelop. Right-click the image and select Generate Embed Code.
public class Main extends Sprite
{
[Embed(source = "../lib/face.png")]
private var ButtonImg:Class;
This code embeds the image in to our project. Whenever you embed an image, you need to define on the next line a class that represents the image you embedded. In this case, our class is called ButtonImg.
Step 3: Adding a TextField
Next, we’ll add a TextField to display how many times we have clicked the button (which will be added next). Add this to Main():
clicksTextField = new TextField();
clicksTextField.width = stage.stageWidth;
clicksTextField.defaultTextFormat = new TextFormat(null, 14, 0, true, false, false, null, null, TextFormatAlign.CENTER);
clicksTextField.text = "Button Presses: " + numClicks;
clicksTextField.mouseEnabled = false;
addChild(clicksTextField);
The code above simply formats the text to display at the top center of our project. Don’t miss how we declared our TextField in line 15.
Step 4: Adding the Button
This code should also go in Main():
var button:BitmapButton = new BitmapButton(ButtonImg);
button.x = stage.stageWidth / 2 - button.width / 2;
button.y = stage.stageHeight / 2 - button.height / 2;
addChild(button);
button.addEventListener(MouseEvent.CLICK,onButtonClick);
When we instantiate our BitmapButton in line 36, we pass our embedded image class as a parameter. This will be used by the BitmapButton class. After this, we can simply treat our BitmapButton instance like any other DisplayObject: we can position it and add a MouseEvent.CLICK listener as we normally would.
Step 5: Making the Button Do Something
Add this event handler function to Main.as:
private function onButtonClick(e:MouseEvent):void
{
numClicks++;
clicksTextField.text = "Button Presses: " + numClicks;
}
The final piece of code in our Main class is the event listener for button clicks. In it, we simply add one to the number of clicks, numClicks, and update the text in clicksTextField.
Step 6: The BitmapButton Constructor
Flip over to BitmapButton.as. First, import these classes:
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.MouseEvent;
Then, declare these:
private var bitmapData:BitmapData;
private const THRESHOLD:Number = 0;
You must make sure that the BitmapButton class extends Sprite, since a Bitmap by itself cannot have any mouse interactivity. (The Bitmap class doesn’t extend InteractiveObject.)
public function BitmapButton(ImageData:Class)
{
var image:Bitmap = new ImageData();
addChild(image);
bitmapData = image.bitmapData;
addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
addEventListener(MouseEvent.CLICK, onClick);
}
In our BitmapButton constructor, we accomplish a couple of important things.
- First, we create a new
Bitmap, called image, from the image class passed as a parameter to the constructor.
- We then add this
Bitmap as a child of our Sprite.
- Next, we set the value of
bitmapData to equal the bitmapData of our image.
- Finally, we add
CLICK and MOUSE_MOVE event listeners.
Step 7: The MOUSE_MOVE Event Listener
private function onMouseMove(e:MouseEvent):void
{
var pixel:uint = bitmapData.getPixel32(mouseX, mouseY);
useHandCursor = buttonMode = ((pixel >>>24) > THRESHOLD);
}
Our simple looking MOUSE_MOVE event listener is the real brains behind our class. Its main purpose is to determine whether the mouse cursor is over a transparent pixel or not. Let’s look at how it does this.
The getPixel32() Function
The first line gets the color and transparency of the pixel that the cursor is currently over. To do this, we use the getPixel32() method of the variable bitmapData (which, remember, is the bitmap data representation of our image).
We must pass an x- and y-coordinate to getPixel32(), so naturally we use the mouse’s position.
The call then returns a uint representing the color and transparency of the pixel at the location we supplied.
Colors in Flash are normally treated as a hexadecimal uint in the format RRGGBB. The first two digits represent the amount of red in the color, the next two, green, and the final two, blue. However, getPixel32() provides us with a special uint representing our pixel in the format AARRGGBB. Here, the first two digits represent the alpha, or the amount of transparency, from 00 (clear) to FF (opaque).
So, for example, FF980000 would represent a fully opaque red color, while 00980000 would represent a fully transparent red color. You’ll typically see these represented as 0xFF980000 or 0x0098000: the “0x” lets you (and Flash!) know that the number is in hexidecimal (0-f), rather than decimal (0-9).
The Bitwise Unsigned Right Shift Operator
At this point, we have a uint called pixel which is holding the color and alpha of the pixel beneath our mouse in the AARRGGBB format. Unfortunately, this is too much information. All we care about is the transparency of this pixel, or the AA part.
You could write a mathematical expression to obtain this section – in fact, int(pixel/Math.pow(16,6)) would work. This is a somewhat awkward statement, though, and slower performance-wise than another option we have: the bitwise unsigned right shift operator, >>>.
Our variable pixel is just a binary number to Flash. We normally write it in hexadecimal just to make it more readable. Without going into too much detail, every digit of a hexadecimal number can be represented by a string of four binary digits, each one either a 0 or a 1. (So, hexadecimal uses digits 0-f, decimal uses 0-9, and binary uses 0-1.)
Say we have a hexadecimal number, D4. In binary, this would be represented as 11010100. Notice how we use eight binary digits for the binary representation: four times as many as in hexadecimal.
With this is mind, let’s examine what the >>> operator actually does. Lets use our previous example, the hexadecimal number D4, or 0xD4 for clarity. Now let’s use >>> as so:
0xD4 >>> 4
Notice that 4 is a normal decimal representation of a number (there’s no “0x” at the start). This expression essentially shifts every binary digit in D4 four places to the right, and forgets about any digit that would go off the end of the number.
0xD4, in binary, is 11010100. Apply four shifts, and it becomes 1101. In hexadecimal, this is 0xD.
If you’re having trouble understanding this, imagine the binary digits as blocks sitting at the right side of a table. The >>> operator is just like pushing the blocks to the right. Here’s our original binary number:
Now here’s our new number, after we do 0xD4 >>> 4 :
Notice how after we shifted 0xD4 by 4 bits, we ended up with just 0xD? That’s not a coincidence. As said before, each hexadecimal digit is made up of 4 binary digits – so, each time we shift it to the right by 4, we essentially knock one hexadecimal digit off the end. You can probably see where we are going with this!
Back to our pixel, in 0xAARRGGBB format. If we shift it by 24, we are actually shifting by 6 hexadecimal digits. This means the RRGGBB portion gets knocked off, and we end up with just the 0xAA part left, which is our alpha component.
A quick numerical example: Say our pixel is equal to FF980000. In binary, this is 1111 1111 1001 1000 0000 0000 0000 0000. (Each group of 4 digits represents one hexadecimal digit.) When we shift this by 24, we simply end up with 1111 1111, or FF, our two transparency digits.
Take a look at it again:
useHandCursor = buttonMode = ((pixel >>> 24) > THRESHOLD);
Okay, the (pixel >>> 24) part makes sense now, but what about the rest?
It’s easy. We check whether our alpha component (the result of pixel >>> 24) is greater than the value of THRESHOLD (which is currently set to 0). If it is, useHandCursor and buttonMode are set to true, which will make the cursor change to a hand. This makes our image seem like a button.
If our alpha component is less than or equal to THRESHOLD, the cursor will remain normal, since the mouse is over a (semi-)transparent pixel. Since we have it set to 0, only fully transparent pixels will not be included as part of our button, but you could set this to, say, 0×80, and then it would display the hand cursor for anything that’s more than half transparent.
Step 8: The CLICK Event Listener
private function onClick(e:MouseEvent):void
{
if (!useHandCursor)
{
e.stopImmediatePropagation();
}
}
The final part of our BitmapButton class is the MouseEvent.CLICK event listener. This function will be called every time our image is clicked, no matter whether that pixel is transparent or not. (Changing the mouse cursor as we did before will not affect the actual MouseEvent.)
So, every time there is a click, we check the useHandCursor property. If it is true, this means the mouse is over a normal pixel in our image, and we don’t need to do anything. This makes sense – the event will then continue on to the event listener we added in Main.as. However, if useHandCursor is false, we have to do something to stop the event from continuing on to other event listeners.
For this, we use the stopImmediatePropagation() method that all Event objects have. Simply put, this stops the flow of the event, and no more event listeners will receive it. So, our event listener function in Main.as will never be called.
Warning: this could have a nasty side effect – any global event listener will not get the event either. If you are worried about this, you can try adding the line parent.dispatchEvent(e.clone()); after e.stopImmediatePropogation(). While this is beyond the scope of the tutorial, I recommend reading more about the event system here.
Conclusion
This wraps up our tutorial! Thanks for reading, and I hope you have learned something new.
A note of caution when using our BitmapButton class – other MouseEvents will still work as normal, since we only dealt with MouseEvent.CLICK. If you wanted, you could use the same technique we used for MouseEvent.CLICK and apply it to other events, such as MouseEvent.MOUSE_DOWN.
Our BitmapButton class allows us to quickly and easily make great buttons from bitmap images with transparency, as we did in this demo. If you have any questions, I’ll be glad to answer them, just leave a comment below.



View full post on Activetuts+