Grant Skinner

The "g" in gskinner. Also the "skinner".

@gskinner

Replace actions on labeled frames in AS3

I recently built a simple class called FrameScriptManager that allows you to set actions on any frame referenced by number or label at runtime from within a bound class. This allows developers to associate code with specific points in timeline animations or transitions, without having to modify the FLA. Because you can reference frames by label, the developer also does not have to worry about designers changing the length of the animation, as long as the label remains in the appropriate location.

This class relies on the undocumented addFrameScript method in AS3, which should be fine as Flash CS3 uses it to insert frame actions, but you should be aware that there is a dependency on an undocumented method prior to using it.

I also built an experimental version of the class that adds additional features, like reverting the frame script and getting or calling the original script. This would have been handy to allow developers to add their own frame actions, but still call the original timeline actions. Unfortunately, because the frameN methods (autogenerated by FlashCS3 for frame actions) are placed in the internal space, these features can only be used on movieclips in the same package as the FrameScriptManager class. As such, I wouldn’t recommend using this version, but I have included it for reference.

Continue reading →

ActionScript 3 Workshop details.

I’ve had a few people ask for more information on the ActionScript 3 workshop I’m running in Toronto at the end of September, and I thought it would be good to clarify the course goals.

This is not a beginner workshop. It is firmly targeted at developers who have a working knowledge of ActionScript 2, and want a fast way to get running with AS3. As such, I will not be covering any basic programming concepts, but instead will focus on differences between AS2 and AS3, and the new features of the language. It will be filled with tips, tricks, best-practices, and gotchas I’ve picked up while applying AS3 to both experimental and commercial projects.

It is lecture format, but with room for some open discussion and Q&A. Attendees will be given comprehensive course notes, and source code for all in-course examples.

Continue reading →

Minor Bug with Bitmap Smoothing in AS3

We recently encountered a problem where bitmap images that we created dynamically were not being properly smoothed when rotated and scaled. We couldn’t see any obvious reason for it – we were setting the container bitmap to smooth, tried every quality setting, but it still looked terrible.

The answer turned out to be super simple, if not immediately obvious. The Bitmap object in ActionScript 3 reverts its .smoothing property to false whenever you change it’s .bitmapData property. Because we were setting up our Bitmap objects in advance, then assigning BitmapData objects to them when they were created, it simply appeared as though smoothing just didn’t work in our project.

Continue reading →

Annoying AS3 Bug with rotation and height/width

I found a very problematic and reproducible bug with ActionScript 3 and simple display object transformations (width, height, rotation), and thought I should document it to save other developers some debugging time.

Put a 200x200px square clip on stage named foo. Add the following code.

foo.height = 100;
foo.rotation = 90;
trace(foo.height);

As expected, this traces 200. It scales the clip vertically, then rotates it, so that it is now 100px wide and 200px high on stage. Now, change the code, and run it again.

foo.rotation = 90;
foo.height = 100;
trace(foo.height);

Unexpectedly, this also returns 200. It should rotate the clip and then apply the vertical scale resulting in a shape that is 100px high and 200px wide on stage. The visual result is identical to the above, when it shouldn’t be.

foo.rotation = 90;
foo.height = 100;
foo.height = 100;
trace(foo.height);

Even stranger, this does trace 100. Unfortunately, the object has been scaled both vertically and horizontally, and is now 100x100px, when it should be 200px wide and 100px high. Seems like the first height assignment gets applied before the rotation, and the second gets applied after the rotation.

Click here to see a (very) simple demo of this behaviour. The left and right blocks should be the same dimensions.

Freaky. I would hazard a guess that this is related to AS3’s weird hybrid of display object properties and transform matrixes.

One workaround would be to work with scaleX and scaleY instead, which are always applied to the original dimensions, and do not account for rotation.

FAVideo Released: Flash Video for JavaScript / AJAX

We had the pleasure of working with Adobe to architect and develop the FAVideo component that Kevin Lynch demoed at AJAXExperience, and which was just released in beta form on the Adobe labs site. It was an interesting project, building a Javascript object that acted as a facade for an embedded Flash video player, and using external interface to communicate between them. The intent is to provide a simple interface for AJAX / Web2.0 developers to embed, control, and play video back in their applications. As such, it has a really robust API for controlling video playback, but it also provides a really simple way for anyone to quickly inject video into their HTML content.

<script lang="javascript">
// simple usage:
var myVideo = new FAVideo("myDiv", "myVideo.flv");
// or a little more customized:
var opts = {skinPath:"SteelOverAll.swf", autoLoad:false, previewImagePath:"preview.jpg"};
var myVideo = new FAVideo("myDiv", "myVideo.flv", 320, 240, opts);
</script>

We had to write some interesting logic to deal with delaying method calls while the player SWF loads, as well as writing a custom event model for subscribing to events like cuePoint, progress, and playheadUpdate in Javascript. We also included support for using any Flash 8 video player skin, youtube-style preview images, built-in Flash player detection, and a ton more. Building the Javascript portion of this component was a somewhat nostalgic experience for me, hacking out classes using prototypes. Made me even happier about AS2 & 3.

The trickiest part of the whole thing was getting it to work properly in Internet Explorer. Apparently there’s a series of nasty issues with IE, Flash player, divs and innerHTML – but that’s a topic for another post.

FAVideo is released under a BSD license, so it can be used for commercial projects. You can download the full source on Adobe Labs. Thanks to everyone at Adobe that tested and provided feedback on the component!

Yggdrasil 3D: World Tree in Papervision 3D and AS3

I’ve been meaning to play with Papervision for awhile, but haven’t found the time. I finally squeezed in a little time to tinker, and the result is Yggdrasil 3D. The Yggdrasil is the world tree in Norse mythology that spans the underworld, earth and the heavens.

The scene is generated entirely programmatically (no prebuilt textures or models). Parts of it were harder than I expected, but I’m starting to get a good grip on it, and plan to do a series of experiments in ActionScript 3 and Papervision 3D.

Continue reading →

Building a Static EventDispatcher in AS3

One of my favorite features of AS3 is the low-level inclusion of EventDispatcher in the AS3 framework. I do not miss the days of including EventDispatcher mix-ins in 80% of my classes in 100% of my projects. I especially like the additional features of the AS3 EventDispatcher: cancellation, custom event types (built in), preventDefault, event phases, etc.

However we have had several AS3 projects that have had a need for an EventDispatcher that is not instance-based. So, without further ado, here is an approach that we have used since our AS2 days:

package {
import flash.events.EventDispatcher;
public class MyClass {
protected static var disp:EventDispatcher;
public static function addEventListener(...p_args:Array):void {
if (disp == null) { disp = new EventDispatcher(); }
disp.addEventListener.apply(null, p_args);
}
public static function removeEventListener(...p_args:Array):void {
if (disp == null) { return; }
disp.removeEventListener.apply(null, p_args);
}
public static function dispatchEvent(...p_args:Array):void {
if (disp == null) { return; }
disp.dispatchEvent.apply(null, p_args);
}
// Other class code
}
}

Note that this differs from a Singleton approach, in that I didn’t want to force a user to extend EventDispatcher (plus I dislike getInstance()). Additionally, some of my fellow developers have noted that using the apply syntax instead of defining all the arguments with types is lazy. Since this runs through an actual EventDispatcher instance, and this class is just a proxy, I didn’t think they were necessary.

I hope someone out there finds this useful. Internally we use it quite often – and it seems to be the most reliable way to add static-access events to a class.


Update
Since I was scolded for not typing the arguments, here is an update, and a sample usage.

package {
import flash.events.EventDispatcher;
import flash.events.Event;
public class MyClass {
protected static var disp:EventDispatcher;
public static function addEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false, p_priority:int=0, p_useWeakReference:Boolean=false):void {
if (disp == null) { disp = new EventDispatcher(); }
disp.addEventListener(p_type, p_listener, p_useCapture, p_priority, p_useWeakReference);
}
public static function removeEventListener(p_type:String, p_listener:Function, p_useCapture:Boolean=false):void {
if (disp == null) { return; }
disp.removeEventListener(p_type, p_listener, p_useCapture);
}
public static function dispatchEvent(p_event:Event):void {
if (disp == null) { return; }
disp.dispatchEvent(p_event);
}
// Public API that dispatches an event
public static function loadSomeData():void {
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
MyClass.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
function onComplete(p_event:Event):void {
trace("Complete!");
}
MyClass.loadSomeData();