Tuesday, March 24, 2009

Video: A Moment of Reflexion

Finally, after great suspense and bitings of nails, Adobe TV has posted my Reflexion Container video. This video was meant to be Part 1 in a sequence of 2 parts, but for reasons that escape me, Part 2 (What a Drag) got posted first. Many things in life are beyond our control: the weather, the things our children say in public, and our cravings for bacon. Apparently, the order of videos posted on Adobe TV is just another random factor in life.

This video shows a container that displays an image along with its reflection. The application has sliders to control the various parameters of the reflection, so that you can see how these parameters affect the realism of the reflection. The reflected image can be changed by clicking on a different thumbnail or, as we saw in the previous Drag and Drop video, by dragging and dropping that thumbnail onto the reflection container.

The techniques used in creating the reflection are not new; I wanted to create this demo to show how they might be used in a sample application container. Also, I wanted to expose the controls to the reflection parameters so that we could see how the various mechanisms affect the result. A couple of resources that I consulted for the reflection technique include the ReflectionPanel demo by Romain Guy (also the photographer of the pictures used in the demo) in a Java book that I've read entitled Filthy Rich Clients and, a bit closer to Flex, an article by Ben Pritchard on the Adobe Devleoper Connection site..

Video being what it is, you may not be able to see some of the impact of the reflection parameters that clearly. For example, when I talk about blurring the reflection to make it more realistic, it actually looks kind of blurry to begin with. Here is the demo itself so that you can play with it directly:

And here is the source code for anyone wishing to see how it actually works. I should point out that it's not the cleanest code, since it was written in a conference rush. The reflection code is the main point of it all, and it's pretty striaghtforward, but the mechanisms of updating the image and recreating the reflection sprite could definitely be cleaner. But in the interests of getting the code out there for people to see, I'm posting it earlier than I might otherwise.

Here's the video - enjoy:

Tuesday, March 17, 2009

Animation Spawning

A developer posted an issue on one of the Flex forums last week that the new Gumbo effects had choppy artifacts when running his test case, especially when compared to similar code that used the Tweener animation library. Being of a sensitive and insecure nature, and wanting to fix any bugs in my effects code, I looked into the problem and discovered some things about animation seemed worth this post.

The Test Case

The original test case used a 3D rotation effect. But between different behavior between Tweener and our FxRotate3D effect and my workspace being a tad torn apart at the moment, I simplified the case down to animating a small square to the current mouse position. Specifically, as you move the mouse around you set a new position to which the the square will animate. If the mouse stops moving, the square will animate toward that position and stop when it gets there. Otherwise, the square will keep animating toward whatever the new position is, changing direction a sthe mouse moves around.

The original test case was set up to start a new animation every time the mouse moved, in a mouse movement handler. Here's that code for the Tweener version:

       private function mouseMoveHandler(event:MouseEvent):void
       {
           Tweener.addTween(rect,
               {x:event.stageX,y:event.stageY,time:2});
       }

where this call animates the rectangle's x and y properties from their current values to the new x/y location of the mouse over a duration of 2 seconds.

Here is similar code for the Flex effects version:

       private function mouseMoveHandler(event:MouseEvent):void
       {
           mover.xTo = event.stageX;
           mover.yTo = event.stageY;
           mover.stop();
           mover.play();
       }

where the Flex mover effect is declared like this:

    <Declarations>
       <easing:Exponential id="exponentialEase" easeInFraction="0"/>
       <FxMove id="mover" target="{rect}" easer="{exponentialEase}" duration="2000"
           animationUpdate="updateHandler(event)"/>
   </Declarations>

Note that the Exponential ease is not in the SDK yet - I created one for this example to mimic the behavior of Tweener's default easing. I will be adding that class sometime soon, along with more of the old easing classes for the Flex3 effects.

The Demos

Here's the Tweener version of the application. If you move the mouse constantly in a particular direction, you can see the square hopping to keep up with it. It's not smooth, but it does aggressively try to keep up, and gets smoother when the mouse stops:

And here's the Flex effects version of the application:

Note that the square seems to move much more slowly when the mouse is in constant motion. In fact, inside of browsers on the Mac (which was the test platform for the person that submitted the original issue), sometimes the square doesn't move at all until the mouse stops moving, at which point the animation engine kicks in and we get a smooth animation of the square.

Now notice that the Flex effects test has a checkbox in the upper-right, cunningly labeled "Smooth Moves." If you check that, you may notice that the animations are a bit snappier, and closer to what you are seeing in the Tweener version. (In fact, I see smoother performance in general with this version than the Tweener version, probably because we force a higher frame rate on animations by posting an updateAfterEvent request whenever there is a Timer event, which will force a render event between the usual enterFrame events). And on the Mac, you should notice that you no longer get complete freezing or jarring delays while the mouse is moving around. All in all, the app is much better behaved when that box is checked.

So what was the fix?

The Fix

It turns out that the original method of spawning new animations for every mouse move is not just more overhead than you really want or need in your animation - it's actually bad practice. Depending on the platform you're on, the frame rate you're getting, the event at which Timer events (which are currently the basis for the Flex effects animation updates) are coming in, and the rate at which mouse events are coming in, you're going to get somewhat unpredictable behavior. What's happening is this:

Between actual animation updates, whether they happen because of a Timer (in the case of Flex effects) or the enterFrame event (in the case of Tweener), you may be restarting your animation one or more times. And depending on when those restarts happen relative to the next animation update, the behavior of those animations may not be what you want. In the case of Flex effects, imagine that you restart your animation 4 times between animation updates because mouse move events came in that many times between updates. When the system finally gets to update the animation, it will use the last one started, which may have started just prior to, or even at the same time as, the current update time. So you may get no movement whatsoever from your animation because according to the time elapsed between the time that you started it and the time you measured it, no time has passed, so the object shouldn't move. Then you start getting mouse events again, and spawning new animations, and you eventually reach the next animation update event only to find that, once again, you are processing an animation that hasn't had any time pass since it was begun.

"But, but, but, " you may justifiably be stuttering, "What about Tweener? Why is that system able to handle this situation better and keep that object moving?"

Why, indeed? The answer is that it does not actually record the true start time for any animation, but rather uses the time used at the last animation update, which is the previous enterFrame event. So when you restart an animation just prior to the next enterFrame event, it doesn't matter that very little or no real time passes between starting it and processing it the first time - the system will process it as if it had been started at the previous enterFrame time. So our little square is able to keep moving around on the screen because the constantly restarted animations are using inflated elapsed times for every calculation.

Note: I'm not saying that Tweener should or should not do it this way; it's just the way that that system happens to work, just as Flex effects work differently by assigning a real start time based on when the effect is started.

But when I realized that that was the key that was causing the stutter I was seeing on Mac browsers for the Flex effects version, I realized that the problem was not in the way that we were handling animations (because I do want Flex effects to reflect the real elapsed time, regardless of when they are started), but rather in how and when these animations were being launched. In particular, it doesn't make sense to launch several animations in between times when we're actually updating the animation. Instead, it makes more sense, both because of the issues here and from the "don't do so freaking much work" standpoint, to track the mouse movement but only cause it to restart animations at other, less frequent intervals.

The "fix" embedded in the "Smooth Moves" variation in the application above does just that: it tracks the mouse movement constantly and then uses the last known position to launch a new animation in the next enterFrame handler (if the position has changed since we started the last animation). In this way, we can be assured that we're letting our animation run at least a little bit before we clobber and restart it with new values, potentially stalling out because we're not allowing things to move at all before we restart a new animation in place of the older one.

Here's the complete code for the Flex effects version - you can see how we handle the animation-spawning logic differently based on the setting of the checkbox. By default, we restart the effect every time the mouse moves. But when the checkbox is selected (smoothMoves.selected == true), then we only record the last mouse position in mouseMoveHandler(), and we defer spawning a new animation until the next enterFrame() call.

<?xml version="1.0" encoding="utf-8"?>
<FxApplication xmlns="http://ns.adobe.com/mxml/2009" width="100%" height="100%"
   enterFrame="enterFrame(event)" mouseMove="mouseMoveHandler(event)"
   xmlns:easing="easing.*">
   <Script>
       <![CDATA[
       import mx.events.AnimationEvent;
      
       private var lastMouseX:int;
       private var lastMouseY:int;
       private var mouseMoved:Boolean;
      
       private function mouseMoveHandler(event:MouseEvent):void
       {
           if (smoothMoves.selected)
           {
               lastMouseX = event.stageX;
               lastMouseY = event.stageY;
               mouseMoved = true;
               if (!mover.isPlaying)
                   mover.play();
           }
           else
           {
               mover.xTo = event.stageX;
               mover.yTo = event.stageY;
               mover.stop();
               mover.play();
           }
       }
       private function enterFrame(event:Event):void
       {
           if (mouseMoved)
           {
               mover.xTo = lastMouseX;
               mover.yTo = lastMouseY;
               mover.stop();
               mover.play();
               mouseMoved = false;
           }
       }
       ]]>
   </Script>
   <Declarations>
       <Power id="powerEase" easeInFraction="0" exponent="7"/>
       <easing:Exponential id="exponentialEase" easeInFraction="0"/>
       <FxMove id="mover" target="{rect}" easer="{exponentialEase}" duration="2000"/>
   </Declarations>
   <Rect id="rect" width="20" height="20">
       <fill>
           <SolidColor color="0xff0000"/>
       </fill>
   </Rect>
   <HBox top="10" right="10">
       <Label text="Smooth Moves"/>
       <CheckBox id="smoothMoves"/>
   </HBox>
</FxApplication>

So: don't spawn animations too aggressively; you may not get the effect you're after from the effect. And note that this approach should work just as well for Tweener (or any other animation engine) as for Flex effects; Tweener only happened to look better in this situation because of its inherent timing behavior, but there would be no reason not to back off and have it spawn less animations too.

p.s.

As a side note, I should point out that another artifact that the original poster ran into was caused by playing the Flex effect multiple times without stopping the previous one(s). You should always, at least in the current Flex effects system, stop() currently playing effects on the same target/property, because otherwise you're effectively giving that property multiple, conflicting instructions at every animation update, as all of the active animations on that property may try to assign different values to it. Tweener does not have this issue because it auto-stops any animations running on that target/property, but Flex effects require you to stop the effect itself. Note that this doesn't mean that you need to stop all effects in the system when you play a new one, or even all effects running on a particular target; the only time that it's an issue is when there are multiple effects running on the same property of the same target(s), as is the case in the example here, where we are always changing the same target's x and y properties.

If you're interested in the full source code, which includes the simple examples above plus the supporting Exponential and Tweener classes used by the examples, here it is. Note that building the Flex effects example requires some recent build of the Gumbo SDK, as it uses classs that only exist in that version of the platform. If you really want to, you should be able to run similar tests with Flex 3 effects (using components instead of the new Gumbo Rect object), since they use the same underlying Timer facility. But the main point of the article was in the demos and explanations; the code is just provided to give a sense of closure.

Friday, March 13, 2009

Video: Flex 3 Effects

Adobe TV has posted a video of me talking about Flex 3 effects. This is basically a subset of the material I covered in my MAX presentation, specifically about the Flex 3 effects architecture: Tween, Effects, Transitions, and so on. No demos this time, just slides, but hopefully helpful if you're trying to figure out how all of these classes and capabilities work together.

Effects are, I think, one of the cooler things about the Flex platform, especially when they make it so easy to provide simple state transitions for a richer user experience. Understanding how they all fit together can help you make more 'effective' use of them.

Enjoy....

Thursday, March 12, 2009

AS34J2: ActionScript for Java Developers, Part Two

The suspense is over, life can return to normal: JavaWorld has posted the second and final installment of my two-part article, ActionScript for Java Developers, which is based on a presentation that James Ward and I did at the Devoxx conference in December.

Part 2 is a bit deeper than Part 1. Now that we've gotten past some of the basic syntax issues in the languages, we're able to get into more complex topics, including Properties, Dynamic aspects of ActionScript, and Functions.

Enjoy...

Thursday, March 5, 2009

Devoxx Talk Posted on Parleys.com: 'The Future of Rich Internet Applications'

The Parleys.com site has just posted the talk that I did at Devoxx in December with Matt Chotin (Flex SDK Product Manager) and James Ward (Flex Evangelist).

Go check out the presentation on the parleys site itself. Parleys is a fantastic Flex application, from the player that you watch the videos in to the publisher that they use to actually create these video/slide/demo-rich presentations. Nice work by Stephan Janssen (founder of Devoxx and Parleys.com) and Benjamin Dobler (developer of the Flex viewer and publisher).

Enjoy...