I wasted almost an entire day this week attempting to figure out why a link started pulsing when activated by a mouse. The link, a 0% alpha “hotspot” or “rollbox” (as it’s sometimes called) movieclip (mouse enabled) with a dynamic textbox (mouse disabled), was listening for onRollOver and onRollOut mouse events. OnRollOver, the link was expected to switch indexes to the front, grow to 3x the original size and then ColorTransform to an active color. The index switch was updated immediately, and the scaleX/scaleY and ColorTransform was a timed action handled by Tweener. With the exception of the re-indexing, these tweens were triggered onRollOut as well, though in reverse. There are obviously a million other ways to handle this, and numerous tweening engines that could be used instead of Tweener, but this was the method I’d used in the past and was most comfortable with.
Upon testing, I found that most of the menu items worked fine, but some “pulsed” or flickered between growing and shrinking, as well as changing color sharply. Moving the mouse over the words while the tween was occurring sometimes seemed to thwart the issue. And some links seemed unaffected by the bug. Also, I noticed that when the link hit the onComplete method of the tween (meaning, it had finished growing to 300% and colorTransforming to the active state), the pulsing stopped.
If you’re more interested in the resolution than the journey, go here.
Tirade
Part of this post, I confess, is a diatribe about unpredictability. Since starting with Flash 2, and progressing through each iteration as my design tool became a development tool (and forced me to adopt development as part of my job description purview), I’d noticed that for a non-sentient, non-emotional, analytical and computational device, ActionScript certainly appeared to be very moody. I’m a technological pessimist, you see. You tell me that you’re going to create an enclosed set of cylinders where you’ll explode a combustable fluid thousands of times each minute and use that pressure to push a piston to turn a rotor to transfer power to turn two axles and four tires at the same speed and create forward motion without blowing us all to kingdom come, I say “here’s your free ticket to crazy town.”
So when it comes to coding, I think the same thing. I can’t help it, it’s just the way I’m wired. Okay, I can buy this:
20 GOTO 10
But, my reliance on Windows and the dreaded blue screen of death has proven that my pessimism in programming’s reliability is well-warranted. And if I, a designer, choose to delve in the world of ones and zeroes, it, too, would produce unpredictable results. Case and point: If I don’t regularly delete ASO files when compiling scripts run on my Linux server, I see results from old and deprecated code. The times on both the server and my computer are identical. Flash must recognize that the code in the ASO files is different from the code in FlexBuilder, so why am I still seeing “Hello World” in FlashTracer when it was removed two iterations ago?
Second fact: Sometimes, my code gets cached and no matter how many times I delete ASO files, my updates aren’t being shown on the screen. And to someone that isn’t confident in his coding skills, and thinks the technology glass is half empty, this is a shockwave (pardon the pun) that ripples through every line of code I write. “This should work,” I think, “but probably won’t.” And when cached files persist and prove myself right—though I should logically realize that it is the cached compiled code that is creating the error and that the code is correct—I grow more and more pessimistic and less and less confident with each keystroke. It wasn’t until a master coder, of whom this blog post mentions consistently and becomes the hero of our fair tale, told me that he’s witnessed the above two issues and needed to go as far as renaming entire project directories to bust the cache, that my confidence was somewhat restored.
Rant over. Back to the bug.
My first course of action was checking to see if the text was truly mouse-disabled, as I’d had problems in the past where my onRollOut / onRollOver function was getting interference from text that scaled or moved under the cursor. When this proved not to be the case, I double-checked my reference book to determine that I truly wanted onRollOut and not onMouseOut. Then I tried setting every item’s mouseChildren to false and traced the MouseEvent Object’s “target” and “currentTarget” result to see what was rolling out. Oddly enough, the MouseEvent Object informed me that I was, indeed, rolling out of the background “hotspot” movieclip when I could clearly see that my mouse was actually there.
Then, after a deep breath, I began to remove the code, line-by-line, and rebuild the menu items, step-by-step. No change. Some (seemingly different) links were pulsing while others appeared to be functioning properly.
With large freshly ripped clumps of hair in each hand and a growing headache, I reluctantly did what I normally do in situations of extreme frustration and anxiety: I recruited the help of a professional (No, not a therapist. A master coder).
Oddly, the most reassuring thing in situations like this, other than willingness to help, is when their recommendations track your previous course of bug-testing actions. It provides that feeling that, while the script is still not functioning properly, at least your methods are strong. The second most reassuring response from this coder was that he thought the site was beautiful and had nice animation. To someone whose focus is design and not development, this went right to my head and alleviated even more stress. Now to the task at hand.
He recommended removing every other listener in the script temporarily, and while I’d done this previously in my line-by-line rebuilding, I retried this technique. Sometimes, in times of frustration, it’s best to be obedient. Especially when experience dictated that frustration also leads to oversights and sloppy troubleshooting. Regardless, nothing.
Then he mentioned something briefly that, in retrospect, would’ve saved me (and, perhaps, him) considerable time:
“Honestly, I’d just try removing as many elements as possible until you find out what’s causing the roll-outs. Sometimes a change in the mc itself causes the rollout to be triggered, like filters or cacheAsBitmap, so you may be forced to add a delay to the onRollOut tween.”
I processed his recommendation superficially and then went on to ramble about how I’d removed all the mouseEnabled, mouseChildren, buttonMode and useHandCursor properties for each item inside each movieclip. Then, without giving it a second thought, I proceeded to complain further. I thought, “If this guy, known world-wide for his open source class libraries, can’t figure this out, what shot do I have on my own?” I hadn’t realized that he already solved my problem and continued to scratch my head and revel in abandonment issues as he left work for the day. Before he left, he gave me the homework of checking the relatedObject method of the MouseEvent object, which is confined to onMouseOver and onMouseOut events only. He also recommended that I create a new Point() onRollOut and then trace a list of objects underneath that point. Both yielded expected results so I sat there, ate an ice pop and tried to decide where to go from there. It was well past the end of the workday and I had nothing to show for it.
Luckily for me (possibly not for him), he popped back online later and I explained my continued frustration. He said that he could only shoot in the dark until he actually saw the files and recommended that I send him a .rar and he’d look at it the following day before work; I gratefully/readily/greedily accepted. His willingness to help had afforded me, in the least, a decent night of sleep knowing that the bug was about to be squashed in the most capable of hands.
Bright-eyed and bushy-tailed, I woke up to his response:
Replace this
Tweener.addTween(mc, {alpha: 1, scaleX:1, scaleY:1, _Blur_blurX: 0, _Blur_blurY: 0, _Blur_quality:2, time:.75, delay:0, transition: "easeInOutQuint"}); |
with this:
Tweener.addTween(mc, {alpha: 1, scaleX:1, scaleY:1, _Blur_blurX: 0, _Blur_blurY: 0, _Blur_quality:2, time:.75, delay:0, transition: "easeInOutQuint", onComplete:function() { this.filters = []; }}); |
The above code was from my animation that brought the link elements onto the stage in the first place, not the tweens associated with onRollOver or onRollOut.
Apparently, filters—which are curiously often neglected in most ActionScript guides—produce unpredictable results in the hit area. To explain it in a way that applies to my case (and, hopefully, yours, if you’ve read this far): It seems that the rendering of elements that have filters (even if it is a 0% blur) is deferred until immediately before the frame actually has to be drawn. Resizing elements with filters make the element lose their hitarea references, so Flash thinks the user has rolled out.
Removing the filter after it fell into disuse—in my case, after the links were on the stage and visible—is good form, allows for more predictable results alleviating the above onRollOut effect, and ultimately lets the code run faster with less memory than it did before. Shame on me, I thought. I know that I should remove items that are no longer necessary and my sloppiness on upkeep and preparation for garbage collection led to a wasted day and a needless pestering of another coder/friend.
The question lingers, though, about onRollOver filters. How can any movieclip or sprite that is expected to respond to MouseEvents do so reliably if the filters produce unpredictable results? Perhaps this is why they’re neglected from the quintessential ActionScript texts.
Hopefully, though, this post will help you if you’ve come across similar issues and reaffirm your mantra of clean coding, sweeping unused and old scraps of code out the door upon proceeding with newer functions and listeners. Confidence shaken, it’s comforting to know that regardless of ASO files that refuse to be deleted, and cached compiled code that doesn’t get destroyed until folders are renamed, ActionScript can still be viewed as a language with logical and expected results. And, if not, there are always smarter people to bug about bugs.
“If this guy, known world-wide for his open source class libraries, can’t figure this out, what shot do I have on my own?”
I completely disagree with that line of thought, but I think it’s difficult to explain why.
Also being “well known” usually means jack shit. Oftentimes it’s just accidental.