Barefoot Development

Flash: Classes and Packages

At Barefoot we have many different kinds of developers. Some come from a Java background. Some have been using Flash since Macromedia purchased it and released it as Flash Version 3. In addition, we work with developers from other agencies or from our clients and that requires project portability.

In this case, portability means the ability to package up a project with all of its pieces and deliver it to someone else in a way that they can begin working on the project without problems caused by missing dependencies.

We also use Subversion as a version control system. One way we use Subversion is to deliver project packages. Because of the way Subversion works, we have to be concious of file system restraints. The majority of the time, this means all of our project files need to live under a main parent directory.

This brings us to the organization of files that make up our projects, in this case Flash projects.

At Barefoot, we borrow a practice from the Java paradigm called Classes and Packages. For in-depth information about using Classes and Packages in Flash, check out Collin Moock's O'Reilly book–Essential Actionscript 2.0 - http://moock.org/eas2/.

In simple terms, Classes are external Actionscript files. Classes are how logic for your Flash application is separated and stored.

Packages are simply a set or group of interrelated classes in a file structure.

So for example, say Barefoot has created a custom Video Player to play FLV files.

We would have a Flash directory to hold all of our files related to the project. This includes any Classes. Default Macromedia Classes can stay in their default directory since we assume anyone else working on this project has Flash, including those core Classes. We also don't add Classes to the default Macromedia directory, all of our custom Classes stay with the project–including our FLA file.

Inside our Flash directory we'll store our FLA(s). We'll also want to store our Packages, remembering that they are just groups of our Classes that are interrelated.

This is where we borrow from Java and other mature language paradigms. We don't want our Packages, and the Classes inside them, to interfere with code from other developers. So, we store them in unique namespaces. The standard is to start this namespace with our company's domain name.

Inside the Flash directory with our FLA is a "Classes" directory. This becomes the root directory of the classpath, or the place where we tell Flash to look for any classes it needs to find. In "Classes", we add a "com" directory. And inside that is a "thinkbarefoot" subdirectory. Get it, thinkbarefoot.com? Now going back to the example, we'll create a "videoplayer" subdirectory inside "thinkbarefoot." Again, this is all covered in Moock's book.

\flash
|
+--\Classes
| |
| ---\com
| |
| ---\thinkbarefoot
| |
| ---\videoplayer
| |
| +--Player.as
| +--Loader.as
|
+---video_player.fla
Inside the "videoplayer" directory will be all of our Classes (*.as), along with maybe some other subdirectories if we break things out further.

Organizing our files like this has two advantages. First, a check-in to Subversion only has to contain one parent directory. Then, if we deliver the project to someone else, all we have to do is zip the Flash directory and they'll have everything they need. That portability is essential when you are working with multiple developers or sending your code to another company.

Without this level of file organization, you may deliver an FLA and some of your logic, but forget one key Class that prevents a future developer from compiling a quick text fix. Adobe has made Actionscript 2.0+ very friendly for use with Classes and Packages. Give them a try, you'll be happy you did.

Mike Krisher, Senior Developer, Barefoot
Doug Smith, Senior Developer, Barefoot

Labels: , , , ,

SlideShowPro - XML attributes

I am using the SlideShowPro component in a Flash piece I am working on and so far it has been a great experience. This is a pretty solid as Sears component.

However, I have the need to extend the XML schema and include additional attributes on my image nodes. It can be done no problem, as discussed here on the SlideShowPro forums. BUT, I noticed that the component converts all attribute names to lowercase.

So, say you want to add an attribute containing the path to download the image, call it "downloadPath." Notice the uppercase P. When retrieving that attribute via the data Object created by SlideShowPro (eventObject.data) the name has to be all lowercase (i.e. eventObject.data.downloadpath). I'm going to stick to just using all lowercase attribute names in the XML to thwart off confusion.

I was going to add this as a reply in the forums, however, they seem to be closed to new registrations?

Michael Krisher, Senior Developer, Barefoot
cross posted here

Labels:

Flash sortOn coolness ...

It's always fun to discover nice little surprises in function lists. I had such an experience when I recently found the sortOn() function within Flash's Array class.

I come from a Java background, and Java's Collections API includes very sophisticated hooks to sort objects in any number of ways. I didn't expect to find that in ActionScript. So, when I had a list of objects that I needed to sort, I was pleasantly surprised to find sortOn(), which sorts an Array of objects.

I frequently create value objects to represent things in Flash applications. In one application, I'm placing a number of animals on the stage. The environment is kinda 3D, so animals that have a lower Y axis value are farther away in the distance, while higher Y values are closer to the viewer. The Y axis value is randomly determined, so the order is not pre-determined.

Here's a simplified version of the Animal value object with only the properties relevant to this post:

class Animal
{
var initX:Number;
var initY:Number;
var initScale:Number;
var animalType:String;
var animalName:String;
// more props

function init():Void
{
// Init stuff ...
}
}

The application reads user-defined animals from the server, and randomly places these animals on the stage. I keep all the Animal objects in an array for later use.

So, I knew that in Java I could sort these Animal objects by implementing the Comparable interface. I was pretty sure I couldn't write a Comparator in ActionScript. But, I decided to check out the Array object just in case.

Then, I found the sortOn() function. Its whole purpose is to let you sort arrays of objects. It has several flavors which you can read about at the link above, but the one relevant to this lets you pass in one or more fields (object properties), and an optional sort type parameter.

Here's an example:

var animals:Array = loadAnimals();
animals.sortOn(["initY"], Array.NUMERIC);

Since initY is a property of every object in the animals array, the sortOn() function sorts the objects on that field. By default, sortOn() sorts in ASCII order, which is fine for strings, but bad for numbers since 100 would be sorted before 99. So, ActionScript offers options like the Array.NUMERIC constant shown above, which tells sortOn() to sort the properties as numbers.

So, thanks ActionScript team for putting that in there -- it was a nice surprise!

Doug Smith, Senior Developer, Barefoot

Labels:

Concerning Media Components and Cue Points

On a recent Flash project (version 7) with talking characters, it became necessary to start and stop animations at specific points during the playback of a sound file. We decided that the most efficient way to manage the calls was via CuePoints which are available in MX 2004 Pro through the Media components.

I placed an instance of the MediaDisplay component on the stage and initialized it thusly:


var myMedia = _root.my_media_component;
myMedia.autoPlay = false;

// Load some sound into the component
// which has been preloaded
myMedia.setMedia("some.mp3", MP3);

// Add CuePoints to the component
myMedia.addCuePoint("start", 7);
myMedia.addCuePoint("stop", 19);

// Create a Cue Point Listener object
var cuePointListener:Object = new Object();

// Call this method when a CuePoint is "heard"
cuePointListener.cuePoint = function(eventObject):Void {
// call the function with the CuePoint's name
handleCuePoint(eventObject.target.mostRecentCuePointName);
}

// Call this method when the sound is complete
cuePointListener.complete = function(eventObject):Void {
trace("I'm all done.");
// do some stuff
}

// Associate/attach the listers to the component
myMedia.addEventListener("cuePoint",cuePointListener);
myMedia.addEventListener("complete", cuePointListener);

// Method to handle each CuePoint
// @param myCue: The name of the "heard" CuePoint
function handleCuePoint(myCue:String):Void {
switch (myCue) {
case "start" :
trace("Start me up.");
// start some stuff
break;
case "stop" :
trace("Stop it, now.");
// stop some stuff
break;
}
}

// Now that everything is ready to go, let's play!
myMedia.play();
trace("The beginning.");


Okay, that was pretty simple -- the sound is playing great and the CuePoints are called in time. But wait, what was that? The sound finished and my CuePoints just fired again. Let's take a look at the output:


The beginning
Start me up.
Stop it, now.
Start me up.
Stop it, now.
I'm all done.


So, something is amiss between the completion of the sound and our listener "hearing" the complete. If we trace myMedia.playheadTime in the complete function, it returns 0. The Media component is automatically rewinding the sound when it finishes but before triggering the complete listener. Blockbuster would be proud. This wouldn't be so bad, but the act of rewinding fires the CuePoints as the sound scrubs back to 0. Luckily, the solution is simple. After a CuePoint is heard, just remove it:


// Call this method when a CuePoint is "heard"
cuePointListener.cuePoint = function(eventObject):Void {
// call the function with the CuePoint's name
handleCuePoint(eventObject.target.mostRecentCuePointName);
// now that the function above has been called, remove the CuePoint
myMedia.removeCuePoint(mediaStreamer.getCuePoint(eventObject.target.mostRecentCuePointName));
}


Not much to it, but the behavior of the MediaDisplay component is so odd that I just had to share.

Bobby Uhlenbrock, Application Developer, Barefoot

Labels: ,