Archive for the Category » Flash «

Friday, September 18th, 2009 | Author: Dave

Recently I did a kids game in Flash that was deployed as a kiosk and which toured a handful of the nations zoos. One of the requirements for the game was that at the end, it would ’sneeze’ on the player – emitting a brief blast of distilled water. After a fair amount of research I found what I needed in SWFKit, one of the leading ‘wrapper’ tools for Flash. By using SWFKit you have all sorts of access to various Windows components like the registry, dialogs, file system and a lot more. I find it invaluable for kiosk work.

The essential component however was an ActiveX component, created by the same SWFKit team. It is called CPortX ActiveX Component and is what allows SWFKit and Flash to communicate with one of your com ports.

So first, you need SWFKit and you can get that at: http://www.swfkit.com

Once you have it installed, you need to get the CPortX ActiveX component, which you get from the same site at: http://www.swfkit.com/swfkit/download.html#tools

Once you have the component installed you’ll be able to send messages to a com port directly from Flash.

The second phase in my research was then how to get the com port to now turn a pump on and off. After much searching I found what I needed in an RS-232 controlled relay from relaycontrollers.com

For this project I used their R15RS – a fairly low cost, single relay controller with a 5 amp rating. I also picked up a power supply for it, and a cable to go between it and the computer’s com port. All together the three pieces were just under $100.

With this simple setup: the ActiveX component and the relay, you can control all sorts of devices from Flash. I however, needed to control a ’sneezer’. What I did for this was to use a windshield washer pump, available at any auto parts store, with the output going to a nozzle, that could be set to spray anything from a stream to an atomized vapor. Think kitchen cleaner nozzle and you’ll get the picture.

Here’s an image of the relay controller that was used:
relay

The labels, NO, COM and NC mean Normally Open, Common, and Normally Closed. When the relay is off, ie the coil is not energized, the Common arm connects to the Normally Closed connection. When the relay is energized, the Common swings over the the Normally Open connection. With that in mind, the pump and its power supply would be connected like so:

relay_schem

When the relay is turned on the Common swings over to Normally Open and provides power to the pump. Simple as that.

The next step is to write a bit of code to send the proper signals to the com port. For this, the code is written within SWFKit and then called from Flash using ExternalInterface.

Within SWFKit choose to make a new file. This will add an Initialize script to the script list, which is called automatically. Within initialize you need to create an instance of the CPortX ActiveX component:

var commx = new ActiveXObject("CPortX.ComPortX");
 
if (commx == null)
{
	Dialogs.msgBox("Please install the CPortX ActiveX control!");
	return false;
}
 
commx.syncMethod = 2;
 
getMainWnd().onClose = function ()
{
	commx.close;
}

First, we try and create an instance of the component. If it’s null, then it hasn’t been installed and a dialog is presented. The syncMethod is then set to 2, which sets the baud rate and such. Finally, the onClose method is created that closes down the component when the projector is closed.

Next, we need two more scripts – one to turn the relay on, and one to turn it off. You do this by right clicking the Script panel and selecting New Script. First – the relayON script:

if (commx.connected) commx.close;
commx.port = "COM4";
commx.open;
commx.writeStr("\xFE\x01");
commx.close;

Using the commx instance created within the initialize script, the port is set to com4, opened and then written to before being closed. By sending the hexadecimal FE and then 01 the relay is instructed to turn on. The FE instructs the relay (or modem) to ‘listen’ and then you send the command. In this case a 1 turns the pump on. Makes sense.

Turning it off is just as simple, sort of. Here’s the relayOFF script:

if (commx.connected) commx.close;
commx.port = "COM4";
commx.open;
 
var ss = new StringStream;
ss.put('\xFE');
ss.put(0);
 
commx.write(ss);
commx.close;

The difference here is that I could not use commx.writestr(“\xFE\x00″); – it simply would not work to send a 0 this way. The great folks at SWFKit provided the fix, telling me to use the StringStream object to send it instead. But the same thing happens – we send the FE telling the relay to listen, and then 0 to turn it off.

Lastly, we just need to call these two scripts from within Flash using ExternalInterface. First I have a turnOn() method which calls the SWFKit relayON script:

function turnOn():void
{			
	ExternalInterface.call("ffish_run", "relayON");			
}

This is called from a sneeze method, which calls turnOn(), and also starts a timer to call turnOff():

function sneeze():void
{		
	turnOn(); //relay			
 
	myTimer = new Timer(400, 1);
        myTimer.addEventListener(TimerEvent.TIMER, turnOff);
        myTimer.start();
}
 
 
function turnOff(e:TimerEvent):void
{	
	myTimer.removeEventListener(TimerEvent.TIMER, turnOff);
	ExternalInterface.call("ffish_run", "relayOFF");			
}

When sneeze() is called, it calls turnON() which turns the relay on, and in turn the pump. A timer is then started which calls turnOff() after 400 ms. The turnOff() method removes the timer listener and calls the relayOFF script within SWFKit. As you might have guessed the 400 ms timing was decided on by simple testing… it gave the pump just enough time to send out a nice little burst of water, aimed right at the player’s face. Believe it or not, it was a big hit.

With this kind of setup – SWFKit and a controllable relay there is a lot of possibility to do things from within Flash that might have otherwise been impossible. The relay company also makes multi-channel relays, which you could use to enable switching of various devices all from the same application. Lots of potential here.

Category: Flash  | 2 Comments
Saturday, September 05th, 2009 | Author: Dave

Here’s a nice little tip for smoothing bitmaps when you’re loading them from an external source. Let’s say you use something like so to load a client logo:

var logoLoader = new Loader();
addChild(logoLoader);
logoLoader.load(new URLRequest("myUrl/myFile.jpg"));
logoLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, logoComplete);

When the jpg has loaded, logoComplete will be called – you can smooth the image using:

function logoComplete(e:Event):void 
{	
	//smooth loaded image	
	var bit:Bitmap = e.target.content;
	if(bit != null){
		bit.smoothing = true;
	}
 
	//resize to fit grid squares
	bit.width = bit.height = SQUARE_SIZE;
 
	//fade in
	TweenLite.from(bit, 1, { alpha:0 } );
}

This can be especially handy if you’re resizing the image by setting its width and height, as shown here.
girl_sample
Here’s a sample of loading an identical 150×150 jpeg image and then resizing to 300×300 with the above code. The one on the left has the bit.smoothing = true; line commented out.

Category: as3  | Comments off
Wednesday, July 01st, 2009 | Author: Dave

Recently, I did a kids game that featured bugs dropping from the sky on parachutes. I handled the vertical motion using script, but thought I’d do the back and forth swinging on the chute using the timeline. Minus the vertical motion I got something like this:

It works, but as you can see Flash doesn’t rotate bitmaps very well, and the client was less than thrilled with it. So, I did a bit of looking and found that if I used pure code I could make a bitmap object from my library items and use the smoothing option. Instead of what I had, I got this:

Much nicer. Here’s the AS3 code I used:

var bug = new Bitmap(new BugA(50,56), "auto", true);
var par = new Bitmap(new Parachute(60,60), "auto", true);
 
var rot = 1.8;
var c = new Sprite();
 
c.addChild(par);
par.x = -30;
par.y = -20;
 
c.addChild(bug);
bug.x = -20;
bug.y = 22;
 
addChild(c);
 
c.x = 100;
c.y = 70;
 
addEventListener(Event.ENTER_FRAME, loop);
 
function loop(e:Event)
{
	c.rotation += rot;
	if(rot > 0){
		if(c.rotation > 25){rot *= -1;}
	}else{
		if(c.rotation < -25){ rot *=-1;}
	}
}

The first two lines are what make the magic happen. A bug and parachute bitmap object is created from simple .png graphics in the library. They have their linkage properties set to export for ActionScript like so:
linkage
Their base class is of type BitmapData because they are images. The final parameter of the Bitmap constructor is the smoothing parameter. By default it is false. Setting it to true, gives us the smooth rotation we’re after.
The remainder of the code creates a Sprite object, places the two Bitmap objects into it, and then places the Sprite so it can be see – with addChild. An Enter Frame listener is added so that the loop function is called. All it does it rotate the object back and forth. All in all, pretty simple and the client was much happier with the result.

Category: as3  | Comments off
Tuesday, June 16th, 2009 | Author: Dave

I’ve been using the uint type in AS3 quite a lot, just because it makes sense for what I’m doing. But yesterday I ran into a gotcha with it. I was using it for a bonus score in a game, that was being decremented every so often by a timer. Since I wanted it to stop when it reached 0, I did the typical:

function updateBonus(e:TimerEvent){
  bonus -= 3;
  if(bonus < 0){
    bonus = 0;
    bonusTimer.removeEventListener(TimerEvent.TIMER, updateBonus);
  }
  bonusText.text = String(bonus);
}

But the field never stopped updating, in fact it would get really big values in it after a while. Like 4294967295

Try this:

var a:uint = 0;
trace(a - 10);
// -10

Odd because I was expecting to see the large values I mention above, not -10. Because I’m not assigning the decrement to a.

var a:uint = 0;
a -= 10;
trace(a);
// 4294967286

There it is. Since a is unsigned, it rolls over to the maximum integer when less than 0. So the test I had (if a < 0) would never be true, and the bonus would eventually get huge. Good for the player, bad for the folks handing out prizes based on score.

So, simply changing the bonus’ type from uint to int fixed the issue. Such a simple thing to be tripped up by.

Category: as3  | Comments off
Wednesday, January 07th, 2009 | Author: Dave

In this tutorial we’ll develop classes to allow enemy ships, in a potential game, to move with various motions, using ActionScript 3’s event system.

Overview:
Motion class – this class will use an algorithm to move a single point around it’s own internal coordinate system. By that I mean the class is not tied to any particular object, it just does it’s thing and programmatically moves a point – it’s up to other objects that subscribe to motion update events to use the class’s x,y values.
Motion Event class – we’ll dispatch a custom event object from the motion class to allow the x,y values to be sent to any registered listeners.
Controller – just a bit of code on frame 1 of an .fla that will create instances of a library clip (the enemy) and set up the motion class to allow the enemies to move.

Getting Started:
To begin start a new .fla file using ActionScript 3. Make a small enemy movie clip (about 30×30) and delete it from the stage. Right-click it in the library and select Linkage. Check export for ActionScript and give it a class name of Invader. Giving the clip a class name will allow you to create instances of it programatically. For ease of use, you should create a new folder for this project and save your file there now. The classes you create will be saved into this same folder.

The Motion Class:
As stated previously, this class will simply move a point around. As it does it will dispatch events so that any objects that are listening (the enemies) can respond appropriately. Select File > New and choose ActionScript file from the dialog. Enter the class code:

package
{
	import flash.events.EventDispatcher;
	import flash.events.Event;
	import flash.utils.Timer;
        import flash.events.TimerEvent;
	import InvaderMoveEvent;
 
	public class MoveRoutine_circle extends EventDispatcher
	{
		private var curX:Number;
		private var curY:Number;
		private var ang:Number;
		private var myTimer:Timer;		
 
		function MoveRoutine_circle()
		{
			ang = 0;
			curX = 0;
			curY = 0;
			myTimer = new Timer(10);
			myTimer.addEventListener(TimerEvent.TIMER, evtMove);
		}
 
		public function move():void
		{
			myTimer.start();
		}
 
		public function pause():void
		{
			myTimer.reset();
		}
 
		private function evtMove(e:TimerEvent):void
		{
			ang += .05;
			if (ang >= 6.28) { ang = 0; }
 
			curX = Math.sin(ang);
			curY = Math.cos(ang);			
 
			dispatchEvent(new InvaderMoveEvent(curX, curY));
		}
	}
}

Save this class as MoveRoutine_circle.as in the same folder as your .fla file. Let’s have a look at the code. First, the class extends EventDispatcher in order to have event capabilities – other objects may add event listeners to this class, and the class can dispatch events as necessary. Within the constructor method, default values are applied to the class variables and a timer object is instantiated. The timer is told to call the evtMove() method every 10 ms. The move() and pause() methods simply start the timer running, and reset it respectively. Note that these are public methods allowing external control of the enemies. Finally, the evtMove() method – it is private because it is only called from within the class – by the timer. It accepts a single parameter, of type EventType, as all event listeners do.
So, within the evtMove() method is the code that does the actual moving of the point. As you may be able to tell, all this code does is to move the point in a circle. The ang variable starts at 0, as set in the constructor, and counts to 6.28 (2 * PI) by .05, before resetting back to 0. In radians this is one complete revolution. As ang is incremented, the sine and cosine are computed and placed in curX and curY. Next, the custom event is dispatched – and curX and curY are sent along to anyone interested.

Note: by playing with the algorithm you can create all sorts of interesting sub-motions. More on that later.

The InvaderMoveEvent class:
As the motion class runs it dispatches new InvaderMoveEvent objects to any registered listeners. Using a custom event here makes sense because it allows you to send the current x,y values directly to listeners. If you were to not use a custom event, the listeners would, after receiving the event, have to poll the motion object to retrieve the x,y values – making for more communication than necessary, and potentially slowing things down.
As before, select File > New and choose ActionScript file from the dialog. Enter the class code:

package 
{
	import flash.events.Event;
 
	public class InvaderMoveEvent extends Event 
	{
		private var _x:Number;
		private var _y:Number;
 
		public static const MOVE:String = "invader_move";
 
		function InvaderMoveEvent(nx:Number = 0, ny:Number = 0)
		{				
			_x = nx;
			_y = ny;			
			super(MOVE);
		}
 
		public function get x():Number
		{
			return _x;
		}		
 
		public function get y():Number
		{
			return _y;
		}
	}	
}

Save this class as InvaderMoveEvent.as in the same folder as your .fla file. As all custom events must do, it extends Flash’s built-in Event class and makes a call to super(eventType) in the constructor – invoking the Event class’s constructor with the data from the custom one. Because I’m using the event to simply carry the x,y data to listeners, and nothing else, I opted out of sending in any of the normal parameters (type, bubbles, etc) and just use the MOVE constant directly in the call to super(). I’ve also not done the override on clone or toString. Two getter methods provide the x,y values to the objects receiving the event.

Let’s quickly see this in action. Add this code to frame 1 of your Flash movie:

var moveCirc = new MoveRoutine_circle();
moveCirc.move();

As you might guess this bit of code creates an instance of the circle motion class and stores it in the variable moveCirc. Next a call to the object’s move() method starts the class’s internal timer which in turns starts making calls to the evtMove() method and begins dispatching the custom event. Underneath the current code add this:

moveCirc.addEventListener(InvaderMoveEvent.MOVE, see);
function see(e:InvaderMoveEvent){
	trace(e.x);
}

What this does is register the timeline function see() to receive the MOVE event type from the class. Test the movie to see the results. You should see a continuous stream of numbers roll by (the points current x) in the output panel. When you’re done you should delete, or comment, those last three lines, as you don’t want the timeline to always listen for motion updates, the enemies will do that themselves.

Note: you could actually create n enemies, sticking references to them in an array. The timeline could receive the motion update and then iterate the array, passing in the values. However, that is essentially bypassing the event system, and inherently slower. Although in testing I got good results with this method, I opted to have individual enemies receive the event directly by registering their own update method.

The Enemy:
Previously, you created a small enemy graphic movieClip and set its class name to Invader. When you test the movie Flash automatically creates the Invader class, because one doesn’t exist in the folder. Click File > New and choose ActionScript file from the dialog. Enter the class code:

package 
{
	import flash.display.MovieClip;	
	import InvaderMoveEvent;
 
	public class Invader extends MovieClip
	{
		private var myX:Number;
		private var myY:Number;
 
		//s is a reference to the current motion class object
		public function Invader(s:*) {			
			s.addEventListener(InvaderMoveEvent.MOVE, doMove);
		}
 
		public function setPos(newX:Number, newY:Number):void
		{			
			myX = newX;
			myY = newY;
		}
 
		private function doMove(e:InvaderMoveEvent):void
		{			
			this.x = myX + e.x;
			this.y = myY + e.y;
		}
	}	
}

Save this class as Invader.as in the same folder as your .fla file. Now when you run the movie, this class will be attached to every enemy invader that is created. Let’s create a single enemy on stage to see how this works. Add these three lines to frame 1 and test the movie:

var p = new Invader(moveCirc);
p.setPos(0,0);
addChild(p);

You should see one enemy ship moving in a small circle. When you invoke the constructor:var p = new Invader(moveCirc); you pass in a reference to the current motion – moveCirc in this case. The Invader class then registers its doMove() method to receive motion updates. The setPos() method allows the code to set the invaders initial position, and updates the internal class variables accordingly. When an event is received, ie when doMove() is invoked the enemy position is updated – note that the enemy is always moved about it’s initial position, if you were to do something like: this.x = this.x + e.x; the objects would end up moving off screen.

Let’s see how more enemies do. Erase those last three lines that add the single enemy and replace them with the following:

for(var i=0; i < 8; i++){
	var v = new Invader(moveCirc);		
	v.setPos(50*i,0);
	addChild(v);	
}

Test the movie and you will see eight ships, all in a row and all moving in a small circle. The code on the frame is, essentially, your controller – it creates an instance of your motion class, and instances of an enemy ship class, and binds them together – by passing a reference to the motion class, to new enemy instances.

Things to try now include modifying the algorithm in the circle class to create differing motions. By creating new classes for your different motions you can create a plugin motion system quite easily. You can also quite easily create a compound motion, where the enemies march across and down the stage, as in the classic space invaders – and still keep their local motion as dictated by the motion class. You can do this by creating a new Sprite, adding the clips to the sprites display list, and then adding the sprite to the main display list. Like so:

var p = new Sprite();
for(var i=0; i < 8; i++){
	var v = new Invader(moveCirc);		
	v.setPos(50*i,0);
	p.addChild(v);	
}
addChild(p);

You can also make bigger circles simply by multiplying the curX and curY values by some number, inside the evtMove() method.

Here’s an interesting variation:

curX = Math.sin(ang) * 10;
curY = Math.tan(ang/2);
Category: Flash  | 4 Comments
Monday, November 10th, 2008 | Author: Dave

A couple of days ago, in the flash.sitedesign forum, someone asked about creating a flashing random thumbnail gallery – and cited http://www.stevenlippman.com/ as what they had in mind. Lucky for you, I thought it would make for a good tutorial.

If you look at that site long enough, you’ll see it’s not actually random at all and its not even dynamic. Probably it’s hand placed movie clips with time line animation. That’s what I call the hard way. The easy way is programmatic, dynamic, and easily modified.

Here’s an example of the finished product

First let’s consider the various components:

  1. Get a list images to use
  2. Create grid of MovieClips to load these images into
  3. Each clip loads images in random order with random timing

Get a list of images to use:
There are a few ways this could be handled. For this tutorial I have chosen to use XML to define the images. XML files are nice because they are human readable and modified by anyone.

Create grid of MovieClips:
A little bit of math will make easy work out of creating a grid of movie clips in any combination of columns and rows.

Each clip randomly loads and displays images:
An ActionScript class that extends MovieClip will allow you to easily hang custom code off of all your script created grid clips.

Part A/2 – Init
First, create a folder for this tutorial. Name it something like ‘flashingThumbs’ and use that as the project folder to place all the files in. Within this folder also create an ‘images’ folder – to house the thumbnails that will be displayed.

Part A – The XML
Copy the following XML, paste into a text file, and save it in your project folder as gallery.xml

<gallery>
	<image title="Title a">a.jpg</image>
	<image title="Title b">b.jpg</image>
	<image title="Title c">c.jpg</image>
	<image title="Title d">d.jpg</image>
	<image title="Title e">e.jpg</image>
	<image title="Title f">f.jpg</image>
	<image title="Title g">g.jpg</image>
</gallery>

Although it’s simple – it could be made even simpler by leaving out the title attribute. However, I added this on purpose, both to show reading of attributes, and to make expansion in the future more straight forward. More on that later.

Don’t worry about the images themselves, you can get all of them in the project .zip file at the end of the tutorial. I even stole them from the Steven Lippman site. Of course you can, and should, use your own thumbs – just make sure they’re all 40×40 like the ones supplied.

In Flash, start a new AS 2.0 movie, set it’s size to 730 x 400, and give it a black background. Add the following script to the first frame of the default layer, Layer 1:

var theXML = new XML();
theXML.ignoreWhite = true;
 
//an array of image objects populated from xml
var gallery:Array;
//folder containing the images that are defined in the xml
var thumbFolder = "images/";
 
//called automatically when the xml is done loading
theXML.onLoad = function(success)
{
  if (success) {
    gallery = new Array();
    theXML.parseXML();
    var len = theXML.firstChild.childNodes.length;
    trace(len);
    for (var i = 0; i < len; i++) {
      var item = new Object();
      item.title = theXML.firstChild.childNodes[i].attributes.title;
      item.image = theXML.firstChild.childNodes[i].firstChild.nodeValue;
      gallery.push(item);
    }
    buildGallery(135);
  }
};
 
theXML.load("gallery.xml");
stop();

Save the movie as gallery.fla in your project folder and compile and run the movie. You should see ‘7′ appear in the output window – the number of images defined in the xml file. if you run the movie without saving first, you’ll get an error about the gallery.xml file not being found. Both the Flash file and the xml file need to reside in the same folder – since no path is specified – just ‘gallery.xml’.

First the gallery.xml file is loaded and when complete the onLoad method of the xml object is called.  If success, then no error occured and the remainder of the function executes. The returned xml is parsed and a for loop is used to iterate the nodes. For each node an object ‘item’ is created and given two properties title, and image – their values being fed from the xml. The item is then pushed onto the gallery array and the loop continues.

When complete you have an array ‘gallery’ with as many items as there are images defined in the xml. Each item in the array is an object with title and image properties. It would look something like:

gallery = [{title:"Title a", image:"a.jpg"}, {title:"Title b", image:"b.jpg"}, {title:"Title c", image:"c.jpg"}, ...{}]

If you want the first image in the array you merely need do:

firstImage = gallery[0].image;

This is the reason I added the title attribute to the xml file. If the xml had contained only the image listing, and no attributes, an array would’ve sufficed. With the title attribute defined, it warranted a more complex data type – an array of objects. Also nice because it gives you the ability to select data by name. If you add more attributes to the xml, simply add them to the object as well, inside the for loop. The underlying gallery array, and any code that consumes it, need not change at all – unless you want to make use of the newly expanded data within the objects.

Don’t worry about the call to buildGallery() – we’ll get to that momentarily.

PS – you can remove the trace from the onLoad as you know it’s working properly.

Part B – Create a grid of clips

First, you’ll need an empty movie clip that will be used as a place holder to load the images into. We’ll use a clip from the library as opposed to creating a clip from code, so that a custom class can easily be linked to each of the clips.

On the Flash stage press Ctrl-F8 – to open the create symbol dialog. Press the advanced button at lower right to display the full dialog:

Give your clip the same settings as is shown – be sure to differentiate between ‘thumb’ and ‘Thumb’ in the identifier and class fields.

Click OK, to close the dialog.

Select the script icon on frame 1, and open the script editor. Near the top of the script, Immediately after the declaration for the gallery array and right before the onLoad definition, add the following:

var thumbsPerRow = 15;
var thumbWidth = 40;
var thumbHeight = 40;
var thumbSpace = 8;
var startX = 10;
var startY = 10;
 
 
function calcPosition(ind:Number):Array
{
  var whichCol = ind % thumbsPerRow;
  var whichRow = Math.floor(ind / thumbsPerRow);
 
  var curThumbX = startX + (whichCol * (thumbWidth + thumbSpace));
  var curThumbY = startY + (whichRow * (thumbHeight + thumbSpace));
 
  return [curThumbX, curThumbY];
}

This is the little bit of math I alluded to earlier. The variable usage should be pretty self evident by their naming. As in the example, we’ll use 15 thumbs per row, and each thumb will be 40×40.  If you do want to use a different thumb size, this is the place to change it. There will be eight pixels between thumbs, and the grid will begin at 10, 10. Simple enough. Using that information the calcPosition function will return the x,y point where any thumbnail should be – given the thumbnails number: 0 – n.

First, the column is found by using the mod operator: % – which returns the remainder of integer division. Dividing the thumb number by how many thumbs per row there are, and then seeing how many are left, gives the column. For example, take the whole first row, thumbs 0 – 14 – you can’t divide any of those by 15 with integer math. What’s left is the number itself: 0 – 14. In the second row, thumbs 15 – 29, it goes like so: 15 goes into 15 evenly, with no remainder – so 0 is returned. 15 goes into 16, with 1 as the remainder. etc, etc. If you create 135 thumbs (0 – 134) then the last thumb goes into column: 134 % 15 = 14. Nifty. From there, getting the x position of the thumb is a bit of simple math.

To get the row, we again divide the thumb number by the number of thumbs per row, but this time we use regular division. If we’re at thumb 134 then 134 / 15 = 8.93333. The floor method is used to get the closest integer less than, or equal to, the target. The floor of 8.9 = 8. So, thumb 134 goes into row 8 – given the 0 based system – that is really row 9. Again, with a bit of math, it’s now easy to find the y value where the thumb should go.

The x,y value is then returned in an array. All we need now is a function that will attach n clips from the library, and position them using calcPosition(). Enter buildGallery(). Paste the following right after the calcPosition() function:

function buildGallery(numThumbs:Number)
{
  //uses the records in the gallery array
  for (var i = 0; i < numThumbs; i++) {
    var p = calcPosition(i);
    var aThumb = this.attachMovie("thumb", "thumb" + i, 10 + i, {_x:p[0], _y:p[1]});
    aThumb.init(gallery, thumbFolder);
  }
}

As you noticed earlier, buildGallery(135) is called once the xml is loaded and the gallery array is built. All buildGallery does is attach the empty thumb clip you created earlier, at the position indicated by calling calcPosition().

Additionally, an init method is called on every thumb created – and both the gallery array, and the thumb folder are passed in. The init method is located in the Thumb class, the class attached to all instances of the thumb clip.

You should save your Flash movie. If you compile and run the movie now, your grid will be created – you just won’t be able to tell since all the attached clips are blank.

At this point, if you’d like to see the grid, you can double-click the empty clip in the library to edit it, add a 40×40 gray rectangle (at 0,0) and then run the movie. You should see a grid of gray clips now. Be sure to remove the rectangle when you’re done.

Part C – Each clip loads images in random order, with random timing

With the grid working, and the gallery xml loading properly the final thing to do is create the Thumb class. This class will extend the MovieClip class, and bestow our empty thumb clips with additional powers. Specifically, they will randomize and store their own copy of the gallery array, and then load the images one after another, at random intervals.

To create the class (Thumb.as) you can use Flash, or any number of external editors. I prefer FlashDevelop myself, which you can find here:

If you’re using Flash, just select File > New > ActionScript File

Add the following:

class Thumb extends MovieClip
{
private var imageFolder:String; //user defined, used by onLoad to load images from the folder
private var myArray:Array; //the thumbs own randomized copy of the gallery array
private var curIndex:Number; //the current index within the gallery array - the current thumb
private var myMCL:MovieClipLoader;
private var myLis:Object; //listener for the movie clip loader
private var myTimer:Number; //random timer that calls doLoad() when it times out
private var usedClips:Array; //used image clips - used to be able to delete old images
 
//CONSTRUCTOR
function Thumb()
{
  myMCL = new MovieClipLoader();
  myLis = new Object();
  myLis.classRef = this;
  myLis.onLoadInit = function(){
    this['classRef'].oli();
  }
  myMCL.addListener(myLis);
}
 
//local onLoadInit
function oli(){
  if(usedClips.length > 1){
    var d = usedClips.shift();
    var i = curIndex;
    d.unloadClip();
    d.removeMovieClip();
  }
  curIndex++;
  if(curIndex >= myArray.length){
    curIndex = 0;
  }
  myTimer = _global.setTimeout(doLoad, Math.ceil(Math.random() * 3000) + 500, this);
}
 
//called by code that attaches thumb
function init(gallery:Array, fold:String)
{
  imageFolder = fold;
  myArray = new Array();
  usedClips = new Array();
  var tempArray:Array = gallery.slice(); //duplicate gallery
  while(tempArray.length > 0){
    var it = tempArray.splice(Math.floor(Math.random() * tempArray.length), 1);
    myArray.push(it[0]);
  }
  curIndex = 0;
  doLoad();
}
 
//internal class method that loads the current image into a new movieClip
private function doLoad(scope)
{
  var cScope = scope == undefined ? this : scope;
  var lastRef = cScope.createEmptyMovieClip("pic" + cScope.curIndex, 10 + cScope.curIndex);
  cScope.usedClips.push(lastRef);
  cScope.myMCL.loadClip(cScope.imageFolder + cScope.myArray[cScope.curIndex].image, lastRef);
}
}

OK, that’s it for the code. Save the ActionScript as Thumb.as – within your project folder. Now, every time an instance of the thumb clip is attached, this class’s constructor (the Thumb() function) will be executed. You don’t have to call it, it runs automatically. The constructor simply initializes a MovieClipLoader so that the thumb can load images. A listener is also created, which calls the class method oli() whenever a new image is loaded.

Recall that the buildGallery() function calls each thumbs init() method as it is attached.  The init() method is passed the main gallery array, and a string giving the name of the folder containing the images. It stores the passed in folder name in a local class variable (so it can be used in doLoad), initializes the two arrays to empty and begins the task of randomizing the passed in gallery array. First, the array.slice method is used, which when passed no parameters returns a duplicate of the original array. You want a duplicate because arrays are passed by reference and you don’t want to alter the original. A while loops is used to iteratively get items at random places in the array, and build myArray. The array.splice method is used to return the random item, and delete it from tempArray. The item is then pushed onto myArray. The while loop continues to execute as long as there items remaining in tempArray. This suffices to shuffle the original array, storing the items in the class variable myArray. The curIndex variable is then reset to 0 and an initial call to doLoad() is made.

The doLoad method first tests the scope variable, and if undefined sets cScope to ‘this’ – class scope. If it is defined then cScope is set to it. This is done because doLoad is also called from the timeOut object and when it is ‘this’ references that object – and not the class. I solved it by passing a class reference to the method, from the timeout object. There are other ways to deal with scope issues in AS2, including the use of the Delegate class, but I chose this method. Note that doLoad is defined to be private because it shouldn’t be called from outside the class.

So, using the cScope variable a new movieClip is created within the empty thumbnail, both its new name and depth are functions of the currentIndex. A reference to the clip is pushed onto the usedClips array and then the loadClip method is called, loading the current image into the new clip.

When the image is loaded the onLoadInit method the MovieClipLoader class will be invoked, and a call to the oli() (short for onLoadInit) class method will be made. I call oli() from onLoadInit in order to invoke it in the class’ scope – otherwise the code within the oli() method would need references to any class variables or methods – because again ‘this’ within onLoadInit will refer to the loader and not the class.

The oli() method is quite simple really, it’s main function is to simply increment curIndex and then set a timeout to call onLoad after some random interval. The other thing it does is process the usedClips array. Whenever the array has more than one clip reference, the first item is removed (using array.shift), the image is unloaded and the clip is deleted. This prevents a stack of ‘pic’ clips from forming, and frees memory as well. Note that the removal of old clips works because new clip references are ‘pushed’ onto the usedClips array, and old clips are removed from the array using shift. Push adds an object to the end of the array, while shift removes an object from the beginning. The result of this push/shift is sometimes known as a LIFO, or Last In First Out.

Calling setTimeout in the _global object space is required from within a class file. It prevents the compiler from complaining that the setTimeout method is not defined.


The movie should now compile and run without problem. If you don’t have a group of thumbnails to use you can use those included in the source zip file below.

Download the source files, as well as thumbnail images here.

Category: Flash  | Comments off
Sunday, November 09th, 2008 | Author: Dave

I thought I’d write a quick summary of some bug hunting goodness over the weekend. For some time I have used a custom file loading class that allows me to pass it an array of targets, and URL’s and it happily loads them one after another and calls a listener when complete. Its always worked great – until this time.
Within the class I pop an element off the top of the passed in loader array, using the shift() method. The shift() method deletes the element – so when the array is empty everything has been loaded. The problem appeared when I later wanted to reference an item in the original loader array, within my movie, and found it was empty. The problem can be seen in this code clip from the class:

private var loaderArray:Array;
 
public function init(loadArray:Array):Void
{
    this.loaderArray = loadArray;
}

Some of you will recognize the issue immediately – and I would have too, had I ever needed to use the original array before. The problem is that arrays are not passed by value. When you set loaderArray = loadArray you are not placing a copy of loadArray into loaderArray. What you are doing is simply setting loaderArray to a memory address, so that it references (points to) the same array. Most of the time this is desirable as it saves on memory, and as long as you’re aware of how it works there is no problem. But sometimes you forget.
So, after finally realizing why my original array was getting erased I corrected it by copying the array instead:

private var loaderArray:Array;
 
public function init(loadArray:Array):Void
{
    for(var i = 0; i &lt; loadArray.length; i++){
        loaderArray.push(loadArray[i]);
    }
}

At least I thought I had corrected it. Anyone see the problem now? The compiler doesn’t see anything wrong either. However, loaderArray doesn’t get anything pushed to it – because it was never initialized. It’s a null object. The compiler doesn’t see anything wrong because loaderArray is typed as array, so push is fine. Fixing is as simple as:

private var loaderArray:Array;
 
public function init(loadArray:Array):Void
{
    loaderArray = new Array();
 
    for(var i = 0; i &lt; loadArray.length; i++){
        loaderArray.push(loadArray[i]);
    }
}

This is only an issue in the AS2 compiler, if you try this in AS3 you’ll get a compiler error like so: Error #1009: Cannot access a property or method of a null object reference. telling you exactly what the problem is. You can’t use the push method on an object that hasn’t been initialized.

PS- this is only an example – you can make a duplicate of an array a lot simpler using the slice method:

private var loaderArray:Array;
 
public function init(loadArray:Array):Void
{
	loaderArray = loadArray.slice();
}
Category: Flash  | Comments off
Wednesday, October 29th, 2008 | Author: Dave

I took this from the old blog because it’s good shit.

I’ve been working on letting users save a jpeg from Flash to their own machine, which for the most part is no biggy even in AS2. The problem area for AS2 is the amount of data that must be sent to the server – typically an array of color values, one for every pixel in the image. So, even a small 200×200 image will generate an array with 40,000 entries – each being a 6 byte hex value. And, when you turn that into a string for posting to the server you get a 1 byte comma added between each entry. So, a 200×200 image turns into approximately a 280K upload – that will likely end up being a 30K jpeg. Which is crap.
So, the trick is to try and minimize the amount of data you send, which can be done in various ways including things like base64 encoding, or using LZW compression. I did try those methods, and while they do work, they were taking far too long (at least in VM1) to do their thing. Uploading the big-ass string was faster than compressing and uploading the small version. I was resigned to just sending the big string, but kept thinking there must be a way to somewhat minimize the impact. That’s when I hit on this simple array compression technique that is reminiscent of RLE.
Here’s the function:

function compressArray(orig:Array):Array{
  var l = orig.length;
  var comp:Array = new Array(); //new compressed array
  for(var i = 0; i &lt; l; i++){
    comp[i] = “”;
  }
  comp[0] = orig[0];
  var lastEqualIndex = 0;
  for(var i = 1; i &lt; l; i++){
    if(orig[i] != comp[lastEqualIndex]){
      //new color
      comp[i] = orig[i];
      lastEqualIndex = i;
    }
  }
  return comp;
}

It works like so – a new array, comp, is created, the same length as the original, and filled with “” – empty strings.
The first item in the new array is set to the first item in the original, and the initial 0 index is stored in lastEqualIndex – since the two arrays are now identical at index 0.
The original array is then iterated starting at the second item in the array – index 1, and going to the end. If the current item in the original array is different from the item in the comp array at the lastEqualIndex, then a new value has been encountered. It is stored in the new, comp, array and the lastEqualIndex is updated to reflect the current index in the loop.
What this accomplishes is creating a new array where runs of duplicate data are eliminated and only the initial value in the run is kept. The other items in the run are kept at their initial empty string values.
Example:

original: [FFFFFF, FFFFFF, AAAAAA, BBBBBB, AAAAAA, AAAAAA, AAAAAA, AAAAAA]
new version: [FFFFFF, , AAAAAA, BBBBBB, AAAAAA, , , ]

original: 55 bytes
new version: 31 bytes

A full 44% reduction

Here’s some actual examples when the array is filled with color values:

As you can see, some images are more compressible than others, as is normal. I couldn’t believe the last image saw an 86% reduction, I expected much worse from it.
The nice thing about this method, aside from the fact that it’s extremely fast, is that the array indexes are preserved and so it’s very easy to reconstruct the original array: If a value in the array is “”, just use the last item (color) that wasn’t empty. Simple as that.

Category: Flash  | 2,802 Comments
Wednesday, October 29th, 2008 | Author: Dave

I’ve decided to move this blog over to our own domain, and also start using WordPress instead of Blogger.


Press the “button” in the lower-right corner to redraw the trees.

Category: Flash  | Comments off