Adobe, MAKE SOME NOISE

I'm iterating on my first test and some of the results are turning out pretty cool. The mxml is coming easier now, but I'm still pretty confounded by what's going on in the API.

For starters, trying to figure out a slider solution took me on a tour of s:Slider, s:HSlider, and finally (past mx:Slider) to mx:HSlider. I haven't kept up on the Flex news that well in the past months so I get the feeling there's some big paradigm shift that's catching me by surprise (something about shifting from the mx package to the new s package for the Spark theme?). I'm guessing that half of these classes will get culled out by launch time, so I guess that's what I get for learning on the beta.

One thing I'm excited about is how quickly you can prototype ideas in here. Getting a webcam up took all of 5 minutes, and throwing out three color pickers was instant. I did spend some time fussing with the width bindings between the slider and the palettes but in a real project I'd probably take the time to design and write a true component for that functionality so I can't complain too much.

Get Adobe Flash player

Gettin’ my Gumbo on

June 16th, 2009

With the big Flash Builder/Catalyst thing going on right now, it seemed like a good time to get myself up to speed on the Flex framework. At the moment, I'm at that stage where everything takes about six times longer to get working than if I just knocked it together in Flash. I keep getting this suspicion that Flex is just VBasic written in ActionScript with some xml in there to gum up the works, but I'm determined to stick it out. (By the way, if anyone has the link to download a copy of the langref, please let me know - waiting for the livedocs is killing me!)

So, for Flex Experiment 0.01, I recreated an old demo I wrote for a paint bucket/magic wand tool. The actual Flex components went together pretty easily - the big issue for me was deciphering which of the 1000+ components in the framework I needed to use. Once that was figured out, the real chore became negotiating the inputs and outputs of the components (s:BitmapImage takes an Object for source and doesn't output a BitmapData anywhere? Really?) - somehow it all seems to work, but the components really are black boxes that developers are not meant to get into.

Anywho - click and drag around to see it in action, and (I'll grudgingly give Flex a gold star here) right click for the source.

Get Adobe Flash player

I was cleaning out an old work directory when I came across some experiments I built back in my AS2 days. Most of them are pretty hacky (proofs of various concepts and interactive mouse toys) but I came across an old bézier path following test. It's not very complex (or even very tricky) but it's got a zen quality and I like it. I didn't crack open the source (AS2!!!) but if anyone is dying for it, I could probably dig it up on request. Also if you're curious, the math for this lives over on my EWIKAL.

Get Adobe Flash player

Drag the three points around to alter the path.

Quick post today. If you're making the jump from timeline coding to class based development (and I definitely encourage you to!) you'll undoubtedly run into this problem. It goes something like this:

  1. Designate a Document Class for your fla - let's call it ProjectMain
  2. Create the ProjectMain class and save it alongside your fla as ProjectMain.as
  3. Set a property of something on stage, let's say myCoolLogo.x = stage.stageWidth / 2;
  4. Compile to receive your TypeError: Error #1009

    Your code is otherwise fine - commenting out that line seems to fix everything. Furthermore the object is right there on stage in your fla – your constructor just refuses to acknowledge it!

    The problem goes back to AS2 prehistory and the top-down/bottom-up problem. If you don't remember that (admittedly it's a little obscure even if you did work in AS2 a lot), here's the gist: Flash is single-threaded, meaning it can only do one discrete task at a time, which includes running your constructor, and parsing everything on stage. In AS2 you could specify whether you wanted to run your code "top down" - meaning, 'run all the code in the top layer, then the next below and so on' or vice versa for "bottom up."

    At this point you should be wondering what this has to do with anything - well let's say you create a variable on layer 10 (top layer) and give it a value - and in layer 1 (bottom layer) you wan't to do something with that value - it's only going to work if you're running top-down. If you run that fla bottom-up you'll execute the layer 1 code first and the variable will be undefined until frame 2. The exact same thing is happening with your constructor in AS3.

    The constructor will always precede any timeline code or bytecode (including positioning things on stage, tweens, &c.) - so you need to be careful with your initialization. It's alright to create new objects and work with them, but you can't query anything that you put down on stage (the same goes for library-linked Classes) until at least one render cycle has passed and allowed all those objects to be generated. Luckily, AS3 has an event for that so it takes some of the pain out.

    Here's how:

    1. // ...
    2.  
    3. //--------------------------------------
    4. // CONSTRUCTOR
    5. //--------------------------------------
    6.  
    7. public function ProjectMain(){
    8. super();
    9. addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void{
    10. e.target.removeEventListener(e.type, arguments.callee);
    11. myCoolLogo.x = stage.stageWidth >> 1;
    12. });
    13. }

    If you're curious about line 39 in there, it's a generic way to remove event listeners - there's a little more detail over on the code page. Also as an added bonus, all the code has been moved into a second function - and since the ActionScript JIT compiler doesn't optimize constructors, there's a good chance that this code will run faster than before.

    I've been messing around with audio lately and it reminded me of a pet peeve so inane that I couldn't help but post about it. Volume controls!

    In AS3, the volume attribute ranges from from 0 to 1. Graphically it's a pretty obvious choice to just link your fader up on a one-to-one relation - the math is straightforward and you can quickly verify that, as you scale up the volume, it gets louder, and when you scale down you approach silence. Easy.

    The problem comes in when you listen to that audio with your fleshy human-ears, which detect sound logarithmically instead of linearly. That means that the perceptual difference in lower volume is much more noticeable than in higher volumes.

    Here's a linear slider:

    Get Adobe Flash player

    1. var v:Number = fader.width / totalWidth;
    2. SoundMixer.soundTransform = new SoundTransform(v);

    Notice that all the real action happens in the first half of the slider - the first 20% is a huge pickup in sound while the last 20% is almost imperceptible. Because your ear is countering the amplification, it's up to you to counter-counteract the faulty hardware (e.g. your user's inferior hearing) and still deliver a good experience. To do that, you need to remap the amplification from a linear input-equals-output model, onto a curve that's roughly opposite to the users perception.

    Here's that same slider remapped to a simple quadratic gain:

    Get Adobe Flash player

    1. var v:Number = fader.width / totalWidth;
    2. SoundMixer.soundTransform = new SoundTransform(Math.pow(v, 2);

    This has a lot more punch to it - the loud end definitely has teeth now, and the quiet end gives you a much finer control. Since we're already working between zero and one, we can employe a simple x² formula without dealing with offsetting or scaling in the equation. To really fine-tune you could use any exponent you want - say 1½ for a half-and-half approach, or 3 to move all the weight to the right side of the slider.


    To sum up, here's a rough graph that I generated drew in photoshop to illustrate the principle. And if you're wondering, the music is Ode to the Bridge Builder from Kyle Gabler's fantastic World of Goo Soundtrack – I'm using it here without permission because it's all I have on my laptop right now – please go buy the game so I get sued less (also because you're a Flash dev and it's an inspiring example of great gameplay)!