The cursor has left the Stage, or has it?

January 28th, 2008 . by polyGeek

A reader asked me if there is a reliable way to determine if the mouse cursor has left the Stage in Actionscript 2. I believe the best approach is to use Javascript to see which object in the DOM has the mouse over it. But it would be nice if there were a reliable way to do it in Actionscript.

Here’s what I came up with which amounts to zero:

  • There are no Stage events to listen to so that doesn’t help.
  • Checking the _xmouse, _ymouse on an interval doesn’t really help because the last position of the mouse cursor is reported when the cursor leaves the Stage.
  • Creating a large MovieClip to cover the Stage and listening for onRollOut on it won’t help because any MovieClips above it will trigger the onRollOut when you rollOver another MovieClip.

It’s rather simple to do with Actionscript 3 but that isn’t an option for my friend.

[ download code ]

package {

  import flash.display.Sprite;
  import flash.events.Event;

  public class MouseOverStage extends Sprite {

    public function MouseOverStage() {
      stage.addEventListener( Event.MOUSE_LEAVE, mouseOutHandler );
    }

    private function mouseOutHandler( event:Event ):void {
      trace( "mouse has left the stage" );
    }
  }
}

Anyone have a suggestion?


The can’t miss conference

January 25th, 2008 . by polyGeek

I’m bummed. There will be a 360Flex conference in one month, February 25-27, and I won’t be there. I went to the first two last year - San Jose and Seattle - and had a fantastic time. With my recent move from Seattle to LA and starting up a freelance business I just don’t have time to go to Atlanta right now.

One of the biggest headaches I had during the first two 360Flex conferences is trying to decide which session to attend at any one time. That’s inevitable that there will be contemporanious sessions that you must see at any conference but more so with 360Flex because of all the great speakers and topics that are covered.

If you’ve never been to a conference then this is the perfect opportunity to get your feet wet. Besides the obvious value of the sessions there are the discussions with your Flex peers in the hallways between sessions and at the end of the day that are invaluable. I’ve learned just as much, if not more, from the conversations with other attendees as I  did during the sessions.

There is no telling what can happen at a conference like this but one thing is certain. You’ll be a better developer for attending.

Hopefully there will be another 360Flex this year in the SoCal area. If so I’ll be first in line to get my ticket. ( hint, hint )


Ted Patrick’s presentation at LA Flex

January 24th, 2008 . by polyGeek

Ted Patrick presented last night at the LA Flex Users Group meeting about the upcoming release of Flex3/AIR. Here are my take-aways:

Release date for Flex3/AIR is in the 4-6 week time period. So the end of February, give or take a week.

$249 to upgrade to the pro version is an incredible value considering you get the memory profiler, advanced dataGrid, new charts, and a few other goodies I can’t remember. The profiler alone is worth the price of the upgrade.

Flex3 will be open sourced when launched. Personally I don’t think open source counts until Adobe mounts a webCam on Ely Greenfield’s forehead. Then, it will be open sourced!

Ted talked about AIR being a desktop platform right now but eventually becoming a device platform. The ubiquitous question was asked, “Does that mean the iPhone will eventually support some version of AIR?” Ted responded by saying something along the lines of, “I know Nothing!” and asking for another question.

So we are faced with this: either Apple is absolutely against supporting AIR in which case Adobe would want to deny any knowledge of Apple’s intent knowing that we developers will read into it that it’s inevitable thus creating a little more interest in AIR. Or, Apple is on board with AIR and work is being done to support it. But in Apple like fashion they have to keep this an ultra secret so that Steve Jobs can make the announcement on stage in front of thousands of sycophants. :-)

Bottom line is this: AIR will be on lots of handheld devices. Some of them similar in functionality to the iPhone. If it isn’t supported on the iPhone itself then Apple will wish it had when the competitors begin to take away their market share with cheaper more robust versions.

I’ve been saying for years that Adobe should build a handheld device that supports Flash/AIR and leave it to third parties to make the UI. Each would be identical with respect to hardware but there could be 10,000 versions of the UI. The cream would rise to the top.

I asked Ted about USB support in AIR. ( In case you didn’t know your AIR apps won’t natively talk to devices connected via USB. That’s because there are lots of differences in how each OS deals with USB. Project Artemis from EffectiveUI helps bridge the gap. Paulius Uza has also made some inroads in this department. )

Ted mentioned that Flash can see USB connected devices such as webCams and Mics. It isn’t impossible, just problematic to make it reliable on all OSes. But it’s something on the table. My hope is that it will be part of AIR 1.5 when AIR supports Linux.

Ted mentioned the internal app at Adobe that they use as a personal directory. It sounds like quite an amazing work and it supports P2P functionality. Basically an AIR client can talk to another AIR client, presumably anywhere. Ummm, I think that’s something that could rock the Casbah.

What’s really cool is that an AIR app can talk to a SWF or Javascript in the browser. That’s great for creating a bridge between a Flex/Flash/Javascript app and your AIR app. You could use this to sync data. For instance you could build an AIR app for offline work. When you go back online you open up your  webApp and tell your AIR app to update it.

Side story: while working at Xbox/Zune I did a prototype for a usability study for interaction between the Zune website and the Zune client. I enabled it so that the user could click something on the website and update something in the client and visa-versa. I mean this is Microsoft. They wrote the browser ( IE ), the OS ( XP/Vista ) and the client ( Zune software ). Turns out that they couldn’t do this without popping up lots of security warnings that couldn’t be shut off. Sound familiar?

I halfheartedly tried to talk the developer into building the Zune client with AIR so that they could have all this amazing functionality - plus cross OS support - but no luck.  Oh well, their loss. :-)

There was lots more about security, modules, framework caching, etc but that has been covered in lots of other places.

Is it late February yet? :-)


Possible Flash player bug

January 19th, 2008 . by polyGeek

Note: I have submitted a bug for this at the Adobe Flash player bug/feature request site where you can vote on it. If/when I hear something back I’ll be certain to share it here.

Since installing the latest release of the Flash player - 9,0,115,0 - I’ve noticed some strange behavior regarding the audio portion of videos. Specifically, everything works normally but every few days I’ll go to watch a video and the audio is gone. I restart the browser and the audio/video work perfectly.

I’m using FireFox 2.0.0.11 on WinXP. I haven’t tested this on IE because it takes a few days for this to happen and I can’t bear to use IE for that long. :-)

I did a Google search on the matter and nothing popped out at me. I’d like to see if anyone else has this issue before reporting a bug.


Particles - API

January 19th, 2008 . by polyGeek

Read the introduction to the Particles class here.
Download Class files

setDustPerSec( countSec:Number )
Set the rate at which dust MovieClips are created. Initially the FramePerSecond is set at 33. So that is the maximum number of dust MovieClips that can be created per second. If you increase the FramePerSecond - with setFPS( n:Number), see below - then you can increase the dust per second up to that same rate.

turnDustOff()
Stops the production of dust.

taperDustRate( sec:Number, countSec:Number ):
Change the rate of dust production over a period of time. This means you can fade the dust production up or down. It’s important to remember that this changes the rate from it’s current value. When you initially create an instance of FairyDust the rate of production is 0. So if you try to fade to 0 over a period of time nothing will happen. You first have to set the rate of production using setDustPerSec() and then fade with taperDustRate().

setFPS( n:Number )
Set the FramesPerSecond. FairyDust uses an interval, not an onEnterFrame. So you can change the speed that it runs internally.

momentumBit( b:Boolean )
By default this is false. If you switch it to true and if the source(s) are moving then the dust MovieClips will inherit the momentum of the source(s).

setAlphaThreshold( n:Number )
When the _alpha of a dust MovieClip passes below this value it is deleted. By default it is set to 10.

setAlphaDelta( n:Number )
The rate at which the _alpha changes over time. By default it is set at 2.

moveSourceWithClip( mc:MovieClip )
If you would like for the source(s) to move automatically in relation to another MovieClip then use this. Just pass a reference to the MovieClip that you want the source(s) to follow.

setDustScale( n:Number )
Change the scale of the dust MovieClips when they are created.

setXYFriction( xValue:Number, yValue:Number )
Dampens the momentum and gravity effects. For instance, if something is moving horizontally there is no built in way to change it’s speed. If the xValue were to be < 1 then the movement along the x-axis would slow down as a piece of dust moves. On the other hand if the xValue were to be > 1 then the dust would speed up over time.

setSpin( low:Number, high:Number )
How much, and in what directio, the individual particles can spin. This will be a random number between the two arguments.


Particles

January 19th, 2008 . by polyGeek

Particles is a class that manages simple MovieClip motion. Obviously by it’s name it can be used to create particles such as falling snow, leaves or anything else. And the MovieClips don’t have to fall. They can also float up. ( Download class files ) ( API documentation )

At it’s heart the Particles class is based on the physics from Kieth Peter’s book Making Things Move.

Here’s the essentials of how it works:

  • You create MovieClip(s) that are linked in the Flash Library - I’ll refer to them as dust.
  • Then you create other MovieClip(s) on the Stage that act as the source of where the linked MovieClips will be emmited from - I’ll refer to them as sources.
  • Lastly you create a MovieClip where the dust can be created dynamically - I’ll refer to that MovieClip as the holder.
  • And if you want you can specify an array of obstacles for the dust to bounce off of.

It’s important to know that there can be any number of dust and source MovieClips but only one holder is needed.

The way the Particles class works is that it attaches dust MovieClips at random intervals depending on the rate you can set.

The dust is always created within the area occupied by one of the source MovieClips that you specify. So if you have a very small source MovieClip then the dust will appear to come out of a point. Or if you have a horizontal line that spans across the Stage as a source then the dust will appear to fall out of that line. That’s something you might do if you wanted to create a snowing effect.

The holder is the MovieClip where the dust is attached at runtime. Each dust particle is always monitoring to see if it still fits within the area that the holder occupies. If it goes outside of that area then it removes itself from the holder so that it doesn’t waste CPU cycles. Therefore you can’t have an emptyMovieClip as the holder because the dust would be removed as soon as it was created. In most cases you would want the holder to be the size of your Stage. But depending on your design it could be smaller or larger as needed.

Lets make some Particles

Here is how you would create an instance of Particles that would look like what you see above. ( download source )

var simpleDust:Particles = new Particles( holder, [sourceMC], ["mote"] );
simpleDust.setDustPerSec( 33 );

The first line creates an instance of the Particles class and the second line sets the rate of dust production at, roughly, 33 per second. I say roughly because it’s all random. You can slow down the rate or speed it up but it will always fluctuate randomly around the value you set.

What’z with the brackets? [ ]

You’ll notice something a little different in the signature. There are brackets around the sourceMC and “mote”. The reason for that is that those are actually arrays that are created inline. That’s because you can have multiple sources and multiple dusts linked in the library. When you have multiples of either then one is randomly selected each time a dust is created.

Here’s an examle.

Here’s the code for that: ( download source )

// balls is an array of strings that is the collection
// of Linkage IDs that you want to use as dust
var balls:Array = ["ball_yellow", "ball_red", "ball_green", "ball_blue"];
// sources is an array of MovieClips - no quotes - that
// are being used as the origins for the dust particles
var sources:Array = [sourceYellow, sourceGreen, sourceRed];
// create an instance of Particles
var multiples:Particles = new Particles( holder, sources, balls );
// set the dust rate so that it will start
multiples.setDustPerSec( 33 );

You’ll notice that these animations don’t slow down no matter how long they run. That’s because once a piece of dust has an _alpha of less than 10 it will automatically delete itself so as to not waste resources. And remember if a dust passes outside the boundaries of the holder it will also delete itself.

There is a lot more that Particles can do that will be covered in later tutorials. And in the near future I’d like to rewrite it in AS3, if I have the time.


A Collection of handy static methods

January 15th, 2008 . by polyGeek

Do you have a collection of methods that you seem to use quite a bit from one project to another? You know, simple things like creating random numbers between a range of two values, or returning the characters in a string that follow a “.” - to get the extension, things like that.

Well I have. I try to keep it small because I use it on most projects for just a few methods here and there so I don’t want it to get bloated. And I gave it the ultra short class name of “Q”. ( If you understand why it’s named Q then kudos to you. )

The Q class ( download ) is full of static helper methods. That means all you have to do is import the class and then call the methods directly.

The import statement looks like this:

import com.polygeek.utils.Q;

You have to put the Q.as file in a folder in your global class path with folder structure of: com/polygeek/utils/Q.as.

Here’s a breakdown of what Q can do for you:

Just say it
This is great for tracing statements in a production environment. What it does is create a TextField on top of everything else in your design. Then it writes the String that you pass in to the TextField. If you add another message later it will just write it to the same TextField.

Plus you can click and drag the TextField around and get it out of the way. By default it will start in the upper-left corner of the SWF.

Here’s an example:
Q.say( "is this working?" );
Q.say( "here's another line.);
Q.say( "click and drag to move me around" );

A few Math tools
var rndNumber:Number = Q.rndRange( beginning:Number, end:Number );
If you need a random number between a set range then use this. For instance, if you needed a random number between 400 and 600 then you would write something like this:

var rndNumber:Number = Q.rndRange( 400, 600 );

Every time that code runs you’ll get a different value between 400 and 600.

You can do negative numbers as well. If you needed a random number between -2 and 2 then just do this:

var rndNumber:Number = Q.rndRange( -2, 2 );

You can use this tool below to see the values rndRange would output.

Q.pythagorean(x:Number, y:Number); // returns a number
Use this if you need the square root of the sum of two numbers squared - that would be the Pythagorean theorem.

Or basically the same thing if you need the distance between two MovieClips - by registration points.
Q.distance(a:MovieClip, b:MovieClip); // returns a number

Getting Physical
If you’ve read Kieth Peter’s Making Things Move book(s) then you’ll recognize these next two methods

Q.newton(a:MovieClip, b:MovieClip); // this applies the result to the two MCs and does NOT return a value

Here’s the nuts and bolts:

Q.newton(a:MovieClip, b:MovieClip):Void {
var dist:Number = Q.distance(a, b);
var force:Number = a.mass * b.mass / dist*dist;
var ax:Number = force * (b._x - a._x) / dist;
var ay:Number = force * (b._y - a._y) / dist;
//
a.vx += ax / a.mass;
a.vy += ay / a.mass;
b.vx -= ax / b.mass;
b.vy -= ay / b.mass;
}

And of course momentum plays a big roll in many of the MTM examples. So this might help:

Q.mo(mc0:MovieClip, mc1:MovieClip):Number {
return ((mc0.mass - mc1.mass) * mc0.vx + 2 * mc1.mass * mc1.vx) / (mc0.mass + mc1.mass);
}

Basic stuff
Draw a border around a MovieClip at runtime. If you don’t pass any arguments then it will draw a white border around the Stage.

Q.stageBorder(strokeWidth:Number, strokeColor:Number, strokeAlpha:Number, mc:MovieClip, fillColor:Number, fillAlpha:Number);

Remove unwanted carriage returns
New with CS3 is the added carriage return at the end of all authoring time TextFields - read read more about it.. That can cause big problems when you are reading the text value of a TextField. This little handy-dandy method will clean that up for you.

var cleanedUp:String = Q.chopLastChar( someTextField.text );

All that does is look at the string that you passed in. If there is a carriage return at the end it will remove it and pass the string back. Otherwise it just passed he string back to you unchanged.

Getting the Time
You pass in a number of seconds and this method will return a formated string of hours:minutes:seconds for you. Take it for a test drive if you want. ( Try inputing something like “3601″ which is 1 hour and 1 second.)

Download convertTime

Usage: var formatedTime:String = Q.timeOut( numberOfSeconds );

Note: I had to use the Q.chopLastChar in the SWF above to get rid of the carriage return.

Doing something to every element of an array

I don’t want to count the number of times I’ve written the code to iterate through every element of an array and perform some action on each element. It’s quick and easy to do but sometimes I get tired of writing:

var len:Number = myArray.length;
for( var i:Number = 0; i < len; ++i ) {
// do something here
}

So I wrote a little method to speed things up a bit.

Q.applyToArray( array:Array, fn:Function );

That little snippit of code will take the array that you passed and iterate through it. In the process it will pass the current element of the array and the current index to that function. So this won’t work for you in every case but probably in most of them.

Here’s the code for the method so you can see better what’s going on and how simple it is:

public static function applyToArray( a:Array, fn:Function ):Void {
var len:Number = a.length;
for( var i:Number = 0; i < len; i++ ) {
fn( a[i], i );
}
}

The downside is that it makes your code a tiny bit harder to read because we’re used to seeing for-loops and this removes them. But you’ll get used to it.

Making Reflections
If you would like to make a reflection of any MovieClip then just use this:

Q.createReflection( source:MovieClip, gradient:MovieClip );
This method takes two MovieClips, the source that you want to be reflected, and the gradient where you want the refection to be located.

The gradient is used to position the reflection and is applied to the reflection as a mask. If you create an alpha gradient then that will in turn fade out the reflection.

Because this is running an interval you can make a reflection of video, or anything that is animated and the reflection will continue to show the visual state of the source MovieClip.

Creating Copies
This method is almost exactly the same as createReflection. But this one obviously doesn’t flip the destination MC over or anything. It just copies it.

Q.createCopy( mc:MovieClip, dest:MovieClip );

Honestly, this and the createReflections shouldn’t really be here. I added them because they were useful at my previous job but I probably won’t use them much anymore, at least not in AS2. I just thought I’d leave them in here in case someone could use them.

Making it draggable
It’s very easy to make a MovieClip draggable with a mousePress/mouseRelease. And it doesn’t require all that much code. But, it could be easier. Try this:

Q.makeDraggable( mc:MovieClip );

Download Draggable Example

You just pass the MovieClip that you want to be draggable and you’re all done. You don’t have to pass in the callback functions unless you need them. In the example you can see that the larger MovieClip has callbacks because the _alpha changes when you press and release the mouse.
Suggestions

What about you. Do you have any suggestions for some useful methods that could be added here? Soon I’ll run through all these methods and convert them to AS3 and publish that class as well.


Delaying the start of tweens with Fuse

January 14th, 2008 . by polyGeek

There are three main ways that you would want to use Fuse to move a group of MovieClips:

  • animate everything one, after another
  • animate everything at the same time
  • animate everything on a staggered delay

Here is an example of the three groups ( download FLA )

The difference in how these work is pretty simple:

If you want each animation to run when the previous one has completed then just add the data for each target MovieClip individually, one after another.

If you want each animation to run at the same time then add all of the MovieClips as an array at the same time.

If you want to stagger the animations so that one starts before the previous one has completed then you push all the MovieClips at the same time, in an array, and add the delay argument to each set of data that you pass to your instance of Fuse.


Actionscript 2 code hinting in CS3

January 13th, 2008 . by polyGeek

This sounds pretty stupid but I used the Flash Actionscript editor for months wondering why the code hinting was always for AS3 even though I was writing AS2 code.

In the upper-left corner of the editor is a dropdown where you can select the type of code hinting you want. All better now.

And please, don’t give me any grief for using the Flash Actionscript editor. It works fine for the rare occasion I write AS2 code. I use Eclipse for all my AS3 work.


Moving a DropShadow with the Mouse

January 12th, 2008 . by polyGeek

If you would like to move a DropShadow, or just about anything else for that matter, as the user moves the Mouse around then try something like this: ( download FLA )

The code in the FLA is very well commented. Here’s the gist of what’s going on:

1 - Start by creating a dynamic DropShadow

import flash.filters.DropShadowFilter;
var ds:DropShadowFilter = new DropShadowFilter(15, 0, 0x000000, 0.8, 5, 5, 1, 3, false, false, false);
myText.filters = [ ds ]; //

This last line is a bit of a cheat because we are passing ds as an array and not pushing it on to the myText.filters collection. We can do this because we only have one filter that we’re using here.

2 - Create a Mouse Listener

import mx.utils.Delegate;
var mouseList:Object = new Object();
mouseList.onMouseMove = Delegate.create( this, updateShadow );
Mouse.addListener( mouseList );

This should look familiar if you’ve created Mouse Listeners before. What might be a little different is the use of the Delegate class. It’s an amazing class that allows you to run functions in a specified scope. Otherwise the listener would be running in the scope of the mouseList object which is pretty useless. Delegate allows us to keep the scope as this so that we can still access functions on our frame here.

Delegate shines even more when you use it with classes. Once you start using it you’ll love it. You can read a bit more about it on polyGeek.com.

3 - Create a function that is called whenever the Mouse is moved

function updateShadow():Void {
var angle:Number = getAngleBetweenPoints();
angle = (angle * 180) / Math.PI;
ds = new DropShadowFilter(15, angle, 0x000000, 0.8, 5, 5, 1, 3, false, false, false);
myText.filters = [ ds ];
}

This function is called every time the Mouse moves.

4 - Create a function that returns the angle between two points. If you don’t pass any points then it will use the position of the Mouse and the center of the Stage as the two reference points.

function getAngleBetweenPoints( x1:Number, y1:Number, x2:Number, y2:Number ):Number {
if( x1 == undefined ) {
x1 = _xmouse;
y1 = _ymouse;
x2 = Stage.width / 2;
y2 = Stage.height / 2;
}
var dx:Number = y2 - x1;
var dy:Number = x2 - y1;
var angle:Number = Math.atan2( dy, dx );
return angle;
}

You have to love atan2. For more about this read Keith Peter’s Making Things Move, page 55.


« Previous Entries