Archive for March, 2009|Monthly archive page

Public, internal, protected, and private

I was trying to explain the difference between some of the major AS3 attribute keywords this past week (public, internal, protected, private) so came up with some analogies to help with the explanations. I figured I’d share… here is your life as an object class:

Public class members are accessible to all objects, everywhere. Think of this as public health. You can observe a sneezing, coughing, unhealthy looking person walking down the street, and chances are that you’ll keep your distance to avoid having them affect YOUR health.

Internal class members are accessible to all objects within a common class package. This would be like your home alarm code. The alarm code is freely available to all members of the household, but not given to outsiders.

Protected class members would be your genes. These are qualities of you that are hidden within the inner workings of your body and are not outwardly visible; however, they will be passed along to your children.

Private class members are reserved exclusively to a single object. This would be your mail. A letter addressed to you may not even be opened by your spouse or your children; it is private information reserved exclusively for you.

Advertisements

Dynamic VU Meter Animation

Raise your hand if you’ve ever had to build a silly little VU (Volume Unit) meter animation for a “sound on/off” toggle… you know the animation that I mean: those little dancing bars representing sound levels on a stereo? While they’re really easy to animate with the timeline, they’re laborious and they create library overhead.

So, for a recent project I finally just wrote out a dynamic VU Meter animation as an AS class. Instance it, drop it onto the stage, and presto! You’ve got dancing bars. This also lets you smoothly transition between dancing bars and a flat line state by toggling the class’ “enabled” property.

Here it is:

package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;

    /**
    * Constructs a fake volume unit meter which can be toggled between dancing bars and a flatline display.
    * Extremely useful for audio toggle buttons when you need an animation to go with the enabled state.
    */
    public class VolumeUnitMeter extends Sprite
    {
        /**
        * Enables / disables the animation.
        * While enabled, the bars will randomly jump up and down.
        * While disabled, the bars will flatline to the minimum height.
        */
        public var enabled:Boolean = true;

        private var _bars:Array;
        private var _from:Array;
        private var _to:Array;
        private var _percent:Number = 0;
        private var _flat:Number = 0.05;

        /**
        * Constructs a fake volume unit meter display (dancing bars).
        * @param numBars Number of bars in the display.
        * @param barWidth Width of each bar.
        * @param maxHeight Maximum height of a bar.
        * @param minHeight Minimum height of a bar during animation or in flat-line state.
        * @param barSpacing Spacing between each bar display.
        * @param barColor Color of the bars.
        */
        public function VolumeUnitMeter($numBars:int=6, $barWidth:Number=3, $maxHeight:Number=25, $minHeight:Number=1, $barSpacing:Number=2, $barColor:uint=0x000000):void
        {
            super();
            _bars = new Array();
            _from = new Array();
            _to = new Array();
            _flat = $minHeight / $maxHeight;

            // draw bar sprite
            for (var $j:int=0; $j < $numBars; $j++)
            {
                var $bar:Sprite = new Sprite();
                $bar.x = ($barWidth + $barSpacing) * $j;
                $bar.y = $maxHeight;
                $bar.graphics.beginFill($barColor, 1);
                $bar.graphics.drawRect(0, 0, $barWidth, -$maxHeight);
                $bar.graphics.endFill();
                addChild($bar);
                _bars.push($bar);
                _from.push(0);
                _to.push(1);
            }

            // draw hit area
            graphics.beginFill(0x000000, 0);
            graphics.drawRect(0, 0, ($barWidth + $barSpacing) * $numBars, $maxHeight);
            graphics.endFill();
            buttonMode = true;
            useHandCursor = true;
            mouseChildren = false;

            _refreshAnimVars();
            addEventListener(Event.ENTER_FRAME, this._onEnterFrame, false, 0, true);
            addEventListener(MouseEvent.CLICK, this._onClick, false, 0, true);
        }

        /** Assigns a new set of animation target percentages. */
        private function _refreshAnimVars():void
        {
            _percent = 0;
            _from = _to;
            _to = new Array();

            for (var $j:int=0; $j < _bars.length; $j++) {
                _to.push(enabled ? Math.max(Math.random(), _flat) : _flat);
            }
        }

        /** @private called upon each EnterFrame cycle */
        private function _onEnterFrame($event:Event):void
        {
            // animate all equalizer bars.
            for (var $j:int = 0; $j < _bars.length; $j++)
            {
                var $from:Number = _from[$j];
                var $to:Number = _to[$j];
                var $bar:Sprite = _bars[$j];
                $bar.scaleY = $from + (($to - $from) * _percent);
            }

            // update animation percentage.
            if (_percent < 1) {
                _percent += 0.20;
            }
            else {
                _refreshAnimVars();
            }
        }

        /** @private called upon mouseClick of the display */
        private function _onClick($event:Event):void {
            enabled = !enabled;
        }
    }
}

Modeling game data

MVC, or “Model-View-Controller” is a pretty hot buzz word in object-oriented programming circles. It’s widely hailed as a solid and robust application design pattern; however, like anything else in the programming world, its really only as good as its execution. If you build a good MVC, it turns into a solid framework to run your game on. But if you just hack something together, then you only make a mess. So, the best approach is just to understand some foundation principals behind the MVC pattern… the most central of which would be the data model.

So, The Model. First, what IS it? Simply put, it is a large structure of objects that organizes and stores all data within your game. Notice that I said “objects” and not “display objects”. One of the most common mistakes that I see made in Flash development is when a program is built utilizing the display as its core. By that I mean that pieces of data are assigned to various display objects, and then those display objects are arranged into a visual hierarchy that may or may not resemble the real structural hierarchy of the data that it represents. What happens then? All these pieces of potentially interconnected data –each attached to a display object– are isolated from  one another by forks in the display list. If one data element wants to work with another, then it needs to chart a path through the display list, or else use some hack solution like a static class accessor.

The best possible rule to observe while building a data model is: keep it entirely disconnected from the display. Think of the display like the skin of an apple. You can always peel the skin off to get at the real body of the fruit. However, when you sprinkle your data into your display list, you’ve essentially just made apple sauce. There’s no way that you’re going to cleanly get your fruit body out of there without bringing skin with it. This makes your core application dependent on the display list, which in turns hurts the scalability, flexibility, and reliability of your application. I note reliability because you’re really shooting yourself in the foot on debugging when you mix your model and your display. Both data and display will have their own unique errors, though a problem will not necessarily be obvious when you can’t tell if the problem is with the data or the display. Quote The Offspring: “You gotta keep em’ separated”.

When starting a new project, the best favor you can do for yourself is to build out your model without ever touching the display. When I kicked off the AS3 Lassie Player, it was a solid month of just building object structures that defined data holders, accessors, and organizers. In that time I never put a single graphic on stage. It’s kind of a backward way of approaching Flash as a technology – given that Flash has gained a huge amount of its popularity through the instant gratification standpoint of immediately getting to see pretty graphics do tricks. However, that temptation to go straight for graphics tends to be a drag in the long run given that your application suddenly seems to collapse under its own weight when it gets to a certain size and complexity (I speak from experience).  When taking the isolated model approach, I’m consistently amazed later at just how easy it is to build the display. All the data is just… well… there! Making graphics behave intelligently with game behavior becomes really easy when you have all of your data laid out nicely in an easy to access configuration.

Now let’s shift gears and talk a little bit technical. I find that the model is best served using EventDispatcher objects as the core class that is extended with custom data elements. Subclass EventDispatcher and build out a unique object with public members for every field of data that you want to store. I’d highly recommend defining all public properties using getter and setter methods, because that allows you to dispatch an event whenever a setter changes a data element… Again, this makes building your display simple: just have each display object subscribe itself to its corresponding data model, and have it update itself whenever its model changes. Suddenly, making things happen within your game becomes easy, because it’s just a matter of setting properties within your centralized model and your display magically reflects the update.