So you’ve done your research and based on your use cases you think Flash development is the way to go. Flash is by no means a dead horse: sure, you can’t develop web-based Flash content and expect it to display (at all) on iOS mobile devices; sure HTML5 + JavaScript + Canvas seems like a pretty good idea (some time in the future); but you know what? Being able to easily, rapidly and often visually develop and deploy apps and games to the web (SWF), desktop (Air) and all major mobile platforms (Air for Mobile) sounds like a pretty good deal to me.
Okay, so you’re cheap. Don’t be shy: admit it. The price tag of Adobe Suite is a little daunting and you don’t have some $500 to get in the game and try it out. This is precisely why God invented the Open Source movement. Welcome: FlashDevelop.
In this short tutorial, written (and I’m not even kidding) with my mother as the intended target audience, we’re going to cover the very very (very) basics of doing some (extremely simple) stuff in Flash using all Open Source stuff, and not a single piece of Adobe software. (Well, you may want to do some Photoshop to create the graphics – go get yourself Photoshop CS2 for free from Adobe.)
Copying bitmap data in ActionScript is pretty easy, but there are a few gotchas, and the Adobe documentation for BitmapData.draw() contains a pretty significant error that can leave you chasing wild geese for some time.
To help me better get at the root of how the BitmapData.draw() actually works, I put together a little sandbox (above) where you can punch in the numbers and see what it does.
I’ll walk through the code after the jump and attempt to explain what’s going on.
Okay folks. Seriously. I don’t like exposing my own stupidity, but here’s a quickie in case it can help anyone. Recently I was completely flabbergasted when, after hours (read: weeks) of developing a game, suddenly Flash (CS4) would hang whenever I did the ol’ CTRL+Enter. And it was just from adding a single line to my code: setScore(6). Nonesense!
After wasting a lot of time rebooting, checking my code, worrying about corrupted FLAs and the like, I discovered the problem was dumb programming error. The compiling was working; the EXECUTION of the SWF was actually hanging.
I had created a nearly recursive nightmare with a typical Event.ADDED gotcha.
Pursuant to a previous post regarding Adobe Acrobat Reader network install, here’s the Flash Player installer that bypasses the Adobe DLM, for those of you that are as paranoid and micro-managerial as I.
I was going through my archives and discovered a number of little demos and tests done in AS2, either to satisfy my own curiosity, or to answer questions posted on Experts Exchange. Here’s another one.
This demo illustrates the use of ExternalInterface to access the URI of the containing web page. This sort of thing becomes useful when handling deep linking within large Flash multi-page sites.
As the title of this post suggests, there is a somewhat unintuitive “feature” in Flash when using inline “frame” scripts to stop() a movie from playing when it first loads. If you use gotoAndPlay() to jump to that frame, the play() part is “over-ridden” by the inline stop() instruction, which is executed AFTER the playhead has been moved to that frame. This came up on kirupa’s forums and the torch was recently taken up by another user, so I decided to investigate and put this thing to bed.
Workaround 1: Redesign
The solution is reasonably simple: tell your designers to insert a “landing” frame containing the stop() instruction in a frame BEFORE the actual frame that you will be jumping to. So, if you were doing gotoAndPlay(1), instead, have the designer insert a keyframe at frame 1, include the stop() action on that frame, and then duplicate that keyframe to frame 2, at which point you can start your animation loop. Now you’ll call gotoAndPlay(2).
Workaround 2: enterFrame()
Okay, so what if you don’t have the luxury of being able to modify the frame structure of the clip(s)? What if it’s rampant throughout your movie? We’ll make a little modification to our method for jumping to the frame in question.
(Bear in mind that this solution specifically addresses ActionScript 2 code):
Who are tempted to register just so you can post a snotty comment that “real Flash developers don’t use frame scripts anyway”, let me get a pre-emptive strike in. First of all, yes, you’re right. Real Flash devs have been trained (I didn’t say “brainwashed”…) to never use frame scripts. BUT, if you’re more than a grubby-haired teen working alone in his basement, you’ll know that in the real world we often work in these things called “teams”, where you have folk of all sorts of different expertise. We work with these guys called “designers” who can barely be convinced to open up the Actions panel and type the word stop followed by open and close brackets (“why!?!” they cry in despair. “Why the brackets??!”) and a (gasp) semicolon.
And these Designer types, they like to preview their flash movies. And they get really distressed when their buttons start flashing wildly and animating on their own. So we appease them by letting them do this one – and only this one – thing in an inline frame script.
Of course the proper way to do things is to call stop() on the movieClip in your Document Class init() method. And in fact, we’ve even found ourselves writing these complicated recursive methods that drill into every movieClip present on init and stop them programmatically. But like I said, often the designers live with the Flash far earlier in its project lifecycle than we do, so they insert all these little stop(); commands all over the place.
And there you have it.
Wow, speaking of “snotty”, those last two paragraphs were pretty snide. If you haven’t shut down your browser, purged my blog from your bookmarks (you did have my blog bookmarked didn’t you?) and removed me from your blogroll, well thanks for indulging my ranting ways. Speaking of ranting ways, just wait until you see my follow-up to my Apple rant. It’s a-brewin….
So I ran into a bit of a snag yesterday when I was working for the first time with the most excellent Greensock TweenLite ActionScript class. Naturally I panicked and blamed everything on the class. Fortunately the author of the class, Jack Doyle was listening in on his forums and responded to (my surprise) within minutes of my posting the query there. He assured me that his class was iron-tight and pointed me in a direction that led me to uncover the error of my ways.
How naive I was! Ah, the shame of it all.
So, to hopefully forestall any future embarassment on the part of you, my reader, who has miraculously stumbled upon this obscure piece of flotsam in the vast ocean that is the InterMegaWeb, let me expound upon the dangers of ActionScript’s pass-by-reference.
But first, let me set the stage by introducing TweenLite a little. Although the class has absolutely no bearing whatsoever on the problem I was experiencing, the way the class is designed kind of allows one to fall into the trap fairly easily, and makes a good example. And besides, it’s a very useful class, so if this is your first introduction to it, I will consider that I did you a service.
TweenLite serves to bolster ActionScript support for tweening things over time without using the Timeline or the Flash IDE. For those of us foolish enough to try to animate things using code, the built-in native Flash Tween class is woefully poor, performance-wise. There are tests to prove it (beware: when testing the native Flash Tween class, be sure to lower the values as it will crash your browser – that’s just how bad the Flash class is!). The TweenLite tween class is a joy to use.
Let’s say you want to tween a MovieClip named myClip across the stage from x = 100 to x = 500, and from y = 100 to y = 400, and you want it done over 5 seconds:
TweenLite.to(myClip, 5, {x:500, y:400});
The previous example assumes that myClip is already at x = 100 and y = 100. Over the next 5 seconds, it will move its way toward (500,400) incrementally each frame. You don’t have to do a damned thing but sit back and watch. Very sweet.
You can even add other, custom parameters to TweenLite to tweak its behaviour. Say you wanted a 1-second delay before the object actually started to move:
TweenLite.to(myClip, 5, {x:500, y:400, delay:1});
Simple. And then of course I had to get in there, try to make things even more user-friendly and that’s when stuff starting blowing up.
So, with great trepidation I unleashed just a tiny little portion of CS4 on my primary production workstation a few weeks ago: Flash CS4 and Dreamweaver CS4. I foolishly decided to work on what was supposed to be a dead-simple mini project (with a mini deadline) using Flash CS4. Sort of a “trial by fire”. Well, I got burnt. Badly.
Turned-on by the new Timeline / Motion Tweening model (they finally listened and brought back the AfterEffects-style animation model from LiveMotion – remember LiveMotion?) I jumped into a very simple project: I was going to do a little “slideshow” of images that would simply fade in, grow a little on the screen and then fade out. Sounds dead simple, right? And in CS3 it would have been a snap. Turns out that it IS a snap in CS4, it just took me over two weeks to figure it out, with Jen DeHaan of Adobe’s patient help. Sounds like the cats on the Adobe Flash team made some pretty funky decisions regarding the new timeline. Let me walk you through what I’ve learned.
Or you can just follow the threads on the Adobe Forums here and here.
In a nutshell the problem is this: by default, the behaviour of the new motion tween in Flash CS4 is that it takes over the entire layer that it is on. As much as the Adobe guys claim that this is “object-level” motion tween, it still completely consumes the layer it’s on in the timeline. What’s worse, by default, it’s actually very hard to mix two different movieClip or Graphic symbol animations on the same layer of the timeline. What occurs is that if you have one symbol with a Motion Tween attached to it in a layer, and then on some later frame in that same layer you try to add a Motion Tween to a different symbol, that symbol gets hijacked and actually physically becomes the earlier symbol. That’s right. You drag a symbol onto a layer that already has a Motion Tweened symbol on it, and as soon as you add Motion Tween to the new symbol – BAM! it becomes the other symbol. In fact, even if you look at that symbol in the Library, it’s been changed!
To me this seems like a basic problem in many Flash-based interfaces. I think Adobe did too, which is why in AS3 they completely revamped their approach to layering display objects.
This leaves those of us stuck back in AS2.0-land (because some customers insist they want their Flash published as FlashPlayer 8! ) scratching our heads. Kirupa, Senocular and other worthies have come up with an interesting technique which keeps a “top-layer” counter, increments it by 2 every time you want to swap depths. While this works perfectly well, there’s something about the technique that, to me (no offense guys: you’re genii), seems like quick-and-dirty (with the emphasis on dirty) code. At some point, I reason, one just HAS to hit that upper layer limit. I’m sure it’s like layer 65538 or something, but still – since you’re using SwapDepths() anyway, why can’t you just find that currently top MovieClip and swap the one you want with it. That way you’re never increasing the top layer count and away you go.
So here’s my take on a bringToFront function. (Note: this is an update to the previous version with some substantial improvements).
Here I’ve added the bringToFront function to the MovieClip prototype, so that you can use it with any movieclip as if it were a native method, like this: myMC.bringToFront();
Can you believe it? You go through the pain of creating a custom cursor in Flash, and then when the user does something pesky like roll the mouse outside the Flash area, your custom cursor (which is really nothing more than a MovieClip that follows your cursor in disguise) stays in its last-known position – wedged somewhere near one of the outer boundaries of your stage, but definitely not looking right, since the “real” mouse is now happily tracking (or whatever it is real mice do) somewhere else on the screen. Two cursors, one big egg in your beer.
After doing some research, it seems the most advanced thinking on the subject (other than those crackpots who tell you to look to external JavaScript to solve the problem – which is bogus) is to use a first-order predictor (velocity) to “guess” (well, “predict” to be precise) where the mouse would be during the next poll. Well, I tried to implement that and I found that the results left somewhat to be desired. Considerably somewhat.
The way this “first-order prediction” business works is: once the mouse leaves the stage, _root.xmouse and _root.ymouse no longer give us meaningful information, because Flash is unable to track the mouse position outside of its own “domain”. So if you’re relying on, say a test to see whether _root.xmouse > 0 to detect whether your cursor has exited stage left, you’re SOL – _root.xmouse will still be reading 4, or 10 or wherever your mouse was LAST time it checked. So what we want to do is to predict where the mouse will be next time, based on where it was last time. In other words: velocity. That’s your “first-order predictor”. And boy does it look good. At first.
As you may or may not remember from your grade X Physics class (I actually didn’t remember – I was too busy oogling my teachers emphatic retort to Newton’s law of gravity – yeah, you Centennial CVI boys know what I’m talking about) velocity can be measured as the change in distance (“delta”) between two points over time. Now since we’re not really dealing with time per se as much as mouse movement over a frame, the equation is simplified quite a bit. As in vx = x2 – x1. So now, if you want to see whether the mouse will be off to the left of the stage, you can just add the velocity into your test to see whether _root.xmouse + vx > 0. Following me? Of course you are.
But, just so I can be clear for myself: if the first time we checked the xmouse was at, say 5 (near the left of the stage) and the second time (now) it’s at 2, x2 – x1 = 2 – 5 = -3. So now we check to see where it will be next time: _xmouse + vs = 2 + (-3) = 2 – 3 = -1 < 0. Great. So the mouse is off the stage. Roll drums, toot horns.
The problem occurs when you “flick” the mouse rapidly off the stage. What’s happening is that now our velocity is changing rapidly, which means that our prediction underestimates where the next position will be, and usually undershoots the mark. If you think about it, you’re not moving the mouse, then all of a sudden you flick it to the left. But, since the mouse is a physical object, it’s subject to the laws of physics, as are you, and so the mouse doesn’t really go from 0 – 60 in an instant. Like a car, it accelerates. Which means that the velocity is increasing over time – so our wonderful first-order prediction is hokey because it’s basing its calculation on a constant velocity.
So I took it one step further and used acceleration in the calculation, rather than velocity. Or rather, in the second poll I still use velocity (because you need three coordinates to calculate acceleration, and at the second poll we only have two points), but in the third poll I discard the velocity predictor for my second-order predictor and get much more accurate results.
Enough mumb-jumbo. Give us the code already, right?
So here’s a real doozie that came from a question someone asked on ExpertsExchange: he had two separate Flash Projectors (EXEs) – that needed to be able to intercommunicate (the first projector needed to know when the second projector had actually finished loading). Since we’re dealing with external projector files that have no dependencies (rather than using the movieClipLoader to load an external SWF into the parent movie), the only thing I could think of that would work reliably was local SharedObjects.
As I put together a solution for this brave soul, I encountered a few interesting challenges, and a few frustrations. Thought I’d document it here because I couldn’t find anyone else who had addresses the intricacies of having two SWF share a SharedObject and monitor the status of that shared SharedObject so they could respond to a change in status.
Here’s the basic principle:
Application 1 creates a local SharedObject and sets an initial status
Application 1 also registers an enterFrame event listener that listens for a status change on the SO
Application 2 accesses the same SO and at some point, changes the status
Application 1′s enterFrame handler detects the status change, and responds to the event.
As I write this, I see there’s an opportunity for a custom event class that does all this, but I’m going to leave that to the real gurus. I don’t pretend to have that intimate a knowledge of ActionScript to be able to pull that off. I should also point out at this time that the original EE user’s question was for AS2, so this solution is only tested in AS2, though since the issues I was running into were related to variable scope, I would only imaging that an AS3 implementation would be easier, if anything.
Here are the challenges I encountered:
how to launch one EXE Projector from another EXE Projector
how to share a SharedObject between two Flash movies (SWFs)
how to continuously monitor the value of a shared SharedObject
If I've learned something useful about the web, it's that you can learn something useful on the web. So every time I learn something useful I think others might find useful I put it here, on my slice of the web.