5 Ways to Cheat at Actionscript

As i see it, there are two ways to approach programming in Flash with Actionscript: the right way, and the “this thing is due at the end of the week” way. Throughout my career, i haven’t enjoyed the luxury of big budgets and generous timelines. The broadcasters are cheap, the teevee producers work mostly on a borrowed dime, and the ad agencies (and everyone else) want to pocket as much as possible for themselves. The result is that a successful independent Flash vendor needs to turn things around FAST.

So while i’m getting to know and understand the best practices of Object-Oriented programming, there are still some tried-and-true methods of finishing work more quickly that don’t obey strict OOP protocol. What follows is a list of pragmatic programming tips – ways to bend the rules, or to leverage the visual tools in the Flash IDE – to speed things up, and to make life easier.

Cheat #1: The Injection Method

The fact that the programming eggheads, the nerderati, have coined a term for this strategy means it can’t be all that bad. The injection method breaks one of the pillars of OOP – encapsulation – but it’s a Hell of a time-saver.

Let’s say you’re building an adventure game. You have an Inventory class and your MainGame class. When the player combines the “dynamite” inventory with the “hammer” inventory item, that action might trigger a death animation. The way you’ve built it, your MainGame class handles all death sequences.

According to the eggheads, the “right” way to do this is for MainGame to instantiate Inventory. In order for Inventory to talk back to MainGame, it should dispatch a custom event, which MainGame listens for:

public class MainGame extends MovieClip
{
    public function MainGame()
    {
          var inventory:Inventory = new Inventory();
          inventory.addEventListener(Inventory.DEADLY_ITEM_COMBINATION, playDeathSequence);
    }
 
    private function playDeathSequence():void
    {
           trace("You have died, because i'm a lousy game developer and i couldn't
                         think of a creative way to solve this situation without screeching
                          the game to a dead stop.");
    }
}

Here’s what the Inventory class looks like:

public class Inventory
{
    public static const DEADLY_ITEM_COMBINATION:String = "deadlyItemCombination";
 
    public function Inventory()
    {
          // Setup stuff goes here - etc etc.
    }
 
    public function combineItems(item1:Item, item2:Item):void
    {
           if(item1.itemType == "hammer" && item2.itemType == "dynaimte")
           {
                 dispatchEvent(new Event(DEADLY_ITEM_COMBINATION));
           }
    }
}

i find it a very time-consuming process to set this up, especially if you need a lot of communication between the two classes. The other asspain is that you can’t specify which deadly item combination triggered the death sequence. What if there is a special death sequence for any dynamite-related inventory screw-up, and a different sequence for any misstep involving the bagOSnakes item? Sure, you can set up some kind of custom event class, but that takes even MORE time, and you’re on a deadline.

With the injection method, you pass a reference to the MainGame class into the Inventory class. Then Inventory can invoke any public methods and properties on MainGame. It breaks encapsulation, sure, but like i said, you’ve got until Friday to make this work, and you probably won’t end up reusing your Inventory class anyway. (Certainly not NOW, you won’t ;)

Here’s how it looks:

public class MainGame extends MovieClip
{
    public function MainGame()
    {
          var inventory:Inventory = new Inventory(this); // pass , or "inject", a reference to the 
                                                                // MainGame class to inventory
    }
 
    public function playDeathSequence(typeOfDeath:String):void
    {
          // inventory calls this public method on MainGame when the time is right 
           if(typeOfDeath == "dynamiteRelated")
          {
               // Play the dynamite death animation
          } else if (typeOfDeath == "bagOSnakesRelated") {
               // Play the bag o' snakes death animation
          }
    }
}
public class Inventory
{
    private var main:MovieClip; // A reference to the MainGame class
 
    public function Inventory(main:MovieClip)
    {
         this.main = main; // Set the instance variable main to whatever's passed into the constructor
    }
 
    public function combineItems(item1:Item, item2:Item):void
    {
           if(item1.itemType == "hammer" && item2.itemType == "dynaimte")
           {
                 main.playDeathSequence("dynamiteRelated");
           } else if (item1.itemType == "bagOSnakes" && item2.itemType == "tickleFeather") {
                 main.playDeathSequence("bagOSnakesRelated");
           }
    }
}

Of course, with anything in programming, there are many ways to skin a cat. If you only ever have one Inventory in your game, you might even make it a static class. The eggheads are going to crucify me for my abuse of the injection method, but that’s alright – i’ve got six dirt-cheap preschool games to build by Friday. i welcome crucifixion with open arms, as it were.

And BOOM! goes the trinitrotoluene

Cheat #2: Dispatching Events from the Timeline

The architects of Actionscript 3 pulled kind of a dick move by rendering the timeline incredibly difficult to deal with. One of the best things about Flash was the amount of complicated graphics and animation stuff it did for you right out of the box, but AS3 robbed us of productivity by making us write a lot of code when we shouldn’t have to.

This disadvantage rears its ugly head when you need to wait for a MovieClip to finish playing its animation. One way to deal with this is to listen to the clip’s ENTER_FRAME or EXIT_FRAME events, and wait until it hits its last frame:

var groovyMovie:GroovyMovie = new GroovyMovie();
addChild(groovyMovie);
groovyMovie.addEventListener(Event.EXIT_FRAME, checkCompletion);
 
function checkCompletion(e:Event = null):void
{
	 if(e.target.currentFrame >= e.target.totalFrames)
	 {
		 // MovieClip has reached the end of its timeline.
	 }
}

That’s fine. But what happens if the clip contains a number of separate animation sequences? You can write a conditional statement inside the checkCompletion() method that looks at the currentLabel property, but that makes your code even thicker:

var groovyMovie:GroovyMovie = new GroovyMovie();
addChild(groovyMovie);
groovyMovie.addEventListener(Event.EXIT_FRAME, checkCompletion);
 
function checkCompletion(e:Event = null):void
{
         var clip:MovieClip = MovieClip(e.target);
 
	 switch(clip.currentLabel)
         {
                case "finishedJumping":
                     doSomethingAfterFinishingJumping();
                     break;
                case "finishedGyrating":
                     doSomethingAfterFinishingGyrating();
                     break;
                default:
                     break;
         }
}

Putting code on the timeline is dirty and bad. Occasionally, i’ll throw in some timeline events (gotoAndPlay(), stop(), etc) but that’s the extent of it. Except in this situation. In this sitaution, if it helps speed things up, i’ll advocate slipping in a dispatchEvent() action on the timeline.

On the salient frame of GroovyMovie:

dispatchEvent(new Event("finishedGyrating"));

And here’s our modified code from elsewhere:

var groovyMovie:GroovyMovie = new GroovyMovie();
addChild(groovyMovie);
groovyMovie.addEventListener("finishedGyrating", doSomethingAfterFinishingGyrating);

No more messy switch statement and – maybe the eggheads can confirm or deny this – i think the code may speed up, because you’re no longer checking that conditional statement every frame. (i’ve never cottoned on to the inner workings of the virtual machine, so if i’m wrong about that, feel free to nerdspank me.)

i’ve been a baaaaad programmer, and i deserve to be punished.

Cheat #3: Positioning Markers on the Stage

One of the most difficult things about AS3 for me, a visual person, is that i suddenly have to lay visual elements like buttons and text fields out in code, instead of on the stage. You get a lot more control over your elements when you manipulate them with code only, and some stuff just downright doesn’t work unless you work solely with code.

What i can’t stand is not knowing where things are going to end up on the stage. i start by positioning something:

widget.x = 173;
widget.y = 221;

Then i compile. When the code places my element on the stage, i soon see it’s off by a longshot. So i go back to the drawing board:

widget.x = 192;
widget.y = 237;

Compile. Check. Damn – this time, i’ve overshot the mark. i repeat this process – set x/y, compile, check, close swf – until it’s in the right place. And then i do the same with some other element. It’s aggravating.

i’ve found one of the fastest ways to cut through this is to create an empty MovieClip in your library and call it “Empty”. Drag it out to the stage where you want the code-created element to exist. Give it the instance name “marker”, or whatever. Then in your code:

widget.x = marker.x;
widget.y = marker.y;

Nothing up my sleeve …

Give the clip the instance name “marker” and position your elements to it.

Later, if you find out you got it wrong, don’t painstakingly tweak the numbers in code. Just grab the marker instance and drag it somewhere else on the stage. Step 4: profit.

Cheat #4: Stealing Color Effect Data

i hope i’m not the only one, but classes like ColorTransform confuse the heck out of me. ColorTransform takes eight arguments:

ColorTransform(redMultiplier:Number = 1.0, greenMultiplier:Number = 1.0, blueMultiplier:Number = 1.0, alphaMultiplier:Number = 1.0, redOffset:Number =0, greenOffset:Number =0, blueOffset:Number = 0, alphaOffset:Number = 0)

Whenever i need a specific outcome from the ColorTransform class, i put a MovieClip on the stage and adjust the Color Effect properties in the Properties panel. If you choose “Advanced” and play with the dials, you may notice that there are eight different parameters you can tweak. These eight params map onto the eight arguments that the ColorTransform class expects.

The numbers in the left column are the multipliers. The numbers in the right column are the offsets.

Here’s the corresponding code, taken from the numbers on the dials. The offset parameters are percentages, so remember to divide the first four offset numbers by 100 (just throw a decimal place in front of them):

var ct:ColorTransform = new ColorTransform(.29, .38, .33, .77, 82, 3, 72, 51);

It’s not exactly a “cheat”, but it does get around this notion that we need to fight tooth and nail to imagine everything through code.

Cheat #5: Guided Layers

This last one is also less of a cheat, and more of a way to get stuff out of codespace and into the more visual Flash environment.

If you’ve ever had to open another programmer’s code and Flash file, you may have been faced with a blank screen. All of the elements are linked in the library, but you don’t know where they’re supposed to go or how they’re supposed to appear without compiling the movie. And if you’ve been hired to fix an incomplete project and the fla won’t compile, you could be in for a world of hurt.

oh, GREAT.

This is usually the path you follow to figure out how the file’s been built:

  1. Check for timeline code in the first frame.
  2. Check for a document class.
  3. Check the library for linkage names to see what gets added to the stage dynamically

In order to be kind to Future-Me, or to anyone who inherits my code if i get hit by a bus, i use guided layers. If you put something on a layer, and then right-click the layer and hit “Guide”, that thing won’t show up when you compile. It’s MUCH friendlier to open up a file and see elements on the stage, so you get some idea of what’s supposed to appear in the file, instead of seeing a blank screen.

Don’t be cruel. Put dynamically-linked stuff on a guided layer.

Important note: If you put code on your timeline (and in nearly all cases, you shouldn’t), your code will still fire even if you Guide out the layer that it’s on.

The stuff on the graphics layer won’t show up, but the actions on the code layer will still fire, even though the layer is guided.

Speed Kills

So those are a few ways that i “cheat” by leveraging the Flash IDE or using “good-enough” practices instead of “best” practices to speed through tight timelines. Do you have any less-than-perfect strategies to get around writing mountains of code, or to make things easier on yourself? i’d love hear them!

20 thoughts on “5 Ways to Cheat at Actionscript

  1. Lucas Araujo

    Nice tutorial. I’ve used the Cheat #4 for everything that’s boring to code, like Filters. But instead of copy the values, I created a function that print on the debug panel all the values of that filter

    Cheers,
    Lucas

    Reply
  2. Abraham

    Nice tricks!
    Specially the one dispatching events from the timeLine, I commonly used local connection for embed swfs (when using swfLoaders) to communicate (in example) the “swfMenu” and the main class, and sometimes I use (this.parent.parent as Object).tehFunction(“param”) :S

    Reply
  3. Amy Blankenship

    You could get the advantages of dependency injection by injecting a callBack function from the Main application. So, either in a constructor or in a setter, you can simply pass in a deathSequence function. If you’ve ever used Flex and you use the List based components, you’ve injected a callBack function when you use a labelFunction. This is perfectly acceptable OOP, and will allow your code to be reused.

    You absolutely can position your objects on the stage and still reference it through code. I give the steps as part of my article on BitmapData here: http://www.insideria.com/2010/02/dealing-with-bitmapdata.html .

    I totally agree that the Flash team did not need to decimate the timeline in order to enable AS3, and since they didn’t bother to document what the workarounds are, we all need to stick together and document our “cheats.”

    Reply
    1. Ryan

      Amy – i like your idea to pass a callback. That’s some smartness – ima try it!

      i couldn’t find the bit in your article where you talked about referencing something you’ve positioned on the stage. i know it can be done, but i was talking more of circumstances where your clip is attached dynamically and you want to get a visual read on where it is. i got out of the habit of dynamically placing things on the stage, because i found i’d get many more errors of stuff not being there when i referenced it with code, usually because i came in too quickly under the added_to_stage event or whatever.

      But i’m with you. Power to the people! Hope to see you at the Flash Gaming Summit … you seem like a smarty!

      Reply
  4. Scarybug

    I frequently use injection because it was how I had to do things in AS2. I also think listening for events might actually run slower.
    Thanks for the color-transform trick! It’s much nicer than my trial-and-error method.

    Reply
  5. ryan

    For #2 you should just do addFrameScript, and call a function when whichever frame you want is in the playhead is shown.

    For #1 When using dispatchEvent you can pass a data object with a custom event, so you can specifically say which death sequence to use. Maybe that’s too much coding for ya, but it works and it’s nice.

    Take care

    Reply
    1. Ryan

      ryan – thanks for the extra tips. One drawback to addFrameScript is that it requires a frame number. i usually animate my stuff to frame labels. For example, i’ll have a character with a walk cycle labeled “walk”, a run cycle labeled “run”, etc. i can pick up and move an entire animation cycle, actions and all, with no consequences. But if i’ve hard-coded the frame numbers, i need to be very careful about how i move those frames around. i can really only safely code my game if my animation is finished.

      – also ryan

      Reply
  6. Rasmus Wriedt Larsen

    As Iain I also thought you would be showing off some of your students codes from the title :D

    I noticed some mistakes in #4, you need to divide by 100, not 10. And you put in “77” for alphaMultiplier and not “.77”. And your picture comment shows you don’t know left and right :D

    I do something like #1 a lot :) But then again I’m just a young hoppyist so far :D

    Reply
    1. Ryan

      RWL – Thanks for catching those! i just type my code straight into the blog, so i don’t always catch the little things. i’ll make those corrections.

      Reply
  7. Peter Strømberg

    Here is my confession…

    For complex filters, I don’t code at all, but use a pseudo movieClip. Easy to set-up and adjust during development:
    (set up movieClip on stage, where it won’t be visible and visually apply wild filter combination)
    myNewText.filters = psuedoClip.filters;

    I use injection daily, but didn’t know that was what it was untill now :)

    Another cheat and cardinal sin I use for quick prototyping is calling the public methods of the main class directly.
    This is because it’s such a pain to set-up custom events and they do seem to slow the execution.
    (nerderati and OOP’ers with weak hearts please look away. Customers, don’t worry, I’m positive I didn’t use this on *your* project…)

    (root as MyMainClass).justExploded(this);
    Using the magic “as” means you get code completion in FlashDevelop and no Errors.

    Though I understand encapsulation, I also know when a class is specific to what I’m working on, and when it’s likely to be re-used. I like to call it “POOP”, that is Primarily Object Orientated Programming, but using every cheat in the book for better performance and/or faster coding.

    Reply
  8. Bret Moretti

    I love this blog and your sense of humor. I really wish you would write a book on AS3 game programming in this same fashion!

    Reply
  9. Amy Blankenship

    Hi, Ryan;

    I’m actually writing a blog post today that will answer your question in more depth. In my BitmapData blog post, I talk about how to get a reference to a display object, but I don’t go into how to get that reference in a movie with multiple frames. Watch my twitter feed for the announcement…I think I’m going to schedule it to come out about Wednesday am (I usually do Sunday, but I was late this week so that would mean 2 in a row). But of course you are right that the big issue is that you need to figure out when an instance is “born” and grab it to instantiate it or whatever. Hint: the ADDED event bubbles, so you don’t need to add an event listener directly to it in order to determine that it was created in response to entering a frame.

    Reply
  10. Pingback: Techwave » Blog Archive » Combining the Timeline with OOP AS3 in Flash

  11. Pingback: Tricks on AS3 « CODE@????

  12. Joe

    I read cheat #1. Sounds like “injection” is just MVC pattern. A view had a reference(“injection”) of the model.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.