Lassie Shepherd Released

October 19, 2009

Lassie Shepherd –a complete SCUMM-style adventure game engine built in AS3– is finally released. It’s only taken me two years and a whole lot of lost sleep… The system still isn’t perfect, but then, it will NEVER be perfect; so this is as good a time as any to release it.

The compiled build is posted on the Lassie website; feel free to download and have a go. I encourage developers to turn to the Lassie Forums to set up a peer-to-peer support community. Unfortunately, I have no availability to commit to technical support. All I can say is —as always— good luck and happy adventuring!


Easy Blowfish Text Encryption

September 2, 2009

All security considerations aside, text encryption is great just for keeping curious editors out of a plain text file. Case of point: I build XML driven Flash games. While I don’t necessarily care if a player “looks under the hood” at the XML data, I would rather that they not try to cheat gameplay by manually tweaking XML configuration. So, a quick encryption of the XML works great to impede manual edits.

So, I’ve always turned to Blowfish for a quick encryption. Blowfish is a two-way cipher that can both encrypt and decrypt text. And thankfully, the fine folks at the AS3 Crypto project on Google code have included an AS3 implementation of the algorithm as part of their open source library. However, the AS3 Crypto library is pretty extensive; and likewise, it takes some extensive research to figure out all the parts and pieces. In my case, I wasn’t so worried about security as I was about having something easy that would generate an encryption. So, I put together this utility class which exposes a simple interface to the Blowfish algorithm and only imports the necessary library items (this import amounts to 11Kb, rather than the 40Kb of the full AS3 Crypto library). You’ll need to download the AS3 Crypto library to go with this utility class.

package
{
 import com.hurlant.util.Base64;
 import com.hurlant.crypto.symmetric.PKCS5;
 import com.hurlant.crypto.symmetric.ECBMode;
 import com.hurlant.crypto.symmetric.BlowFishKey;
 import com.hurlant.crypto.symmetric.ICipher;
 import com.hurlant.crypto.symmetric.IPad;
 import flash.utils.ByteArray;

 public class Blowfish
 {
 /**
 * Encrypts a string.
 * @param text  The text string to encrypt.
 * @param key  A cipher key to encrypt the text with.
 */
 static public function encrypt($text:String, $key:String=""):String
 {
 try
 {
 var $output:ByteArray = new ByteArray();
 $output.writeUTF($text);
 var $pad:IPad = new PKCS5();
 var $cipher:ICipher = _getCipher( $key, $pad );
 $pad.setBlockSize( $cipher.getBlockSize() );
 $cipher.encrypt( $output );
 $cipher.dispose();
 return Base64.encodeByteArray( $output );
 }
 catch ($error:Error)
 {
 trace("An encryption error occured.");
 }
 return null;
 }

 /**
 * Decrypts an encrypted string.
 * @param text  The text string to decrypt.
 * @param key  The key used while originally encrypting the text.
 */
 static public function decrypt($text:String, $key:String=""):String
 {
 try
 {
 var $input:ByteArray = Base64.decodeToByteArray( $text );
 var $pad:IPad = new PKCS5();
 var $cipher:ICipher = _getCipher( $key, $pad );
 $pad.setBlockSize( $cipher.getBlockSize() );
 $cipher.decrypt( $input );
 $cipher.dispose();
 $input.position = 0;
 return $input.readUTF();
 }
 catch ($error:Error)
 {
 trace("A decryption error occured.");
 }
 return null;
 }

 /** @private builds a Blowfish cipher algorithm. */
 private static function _getCipher( $key:String, $pad:IPad ):ICipher {
 return new ECBMode( new BlowFishKey(Base64.decodeToByteArray( $key )), $pad );
 }
 }
}

Implementation of this Blowfish utility class is extremely easy. Just import the class, then call its static encrypt() and decrypt() methods. The first param of each method is the text to encrypt, and the second params are the encryption key. When decrypting text, you must provide the same key that the text was originally encrypted with. Here’s a sample implementation:

import Blowfish;
var $key:String = "lockme";
var $encryption:String = Blowfish.encrypt("Don't read this text!", $key);

trace( $encryption );
// return: "sm63oSsAgk0T8TWad0vjRMv5KV7COH80"

trace( Blowfish.decrypt($encryption, $key) );
// return: "Don't read this text!"

Flash Accessibility

August 28, 2009

I’ve been doing some work for the National Park Service recently, and it’s gotten me into Flash accessibility. Accessibility is a big deal for government clients because all “.gov” websites mandate 508 compliance – which requires that all content be visible to screen readers, like JAWS.

While it’s pretty easy to get Flash content exposed to a screen reader, it’s fairly tedious to get the presentation flowing nicely with both with visual controls and accessibility controls. It doesn’t help that Flash’s accessibility documentation is fairly slim and there aren’t a lot of developers discussing it. So, after a few days worth of development and testing on the subject, I’ll share my findings.

1) Make DisplayObjects accessible.

Start by giving each button an “AccessibilityProperties” object. The AccessibilityProperties object can have a name and description assigned to it. From what I can tell, the “name” field is the key piece of content given that it’s automatically read when the button gets focus. I never found a way to access the “description” field through my screen reader (but then I’m not a JAWS power user either). Also, enable “forceSimple” on the AccessibilityProperties object so that none of the object’s children are read. Otherwise, the screen reader will read a button’s text content.

2) Restrict tab ranges

Flash will, by default, step through all buttons on stage. However, chances are that you won’t want every single control included within the accessible presentation. So, use “tabEnabled” and “tabIndex” (properties of InteractiveObject) to control which buttons are allowed to receive tab focus. Set “tabEnabled” to false on all buttons that are not part of the accessible presentation, or just set “tabChildren” (property of Sprite) to false on a high-level display container to completely disable tabbing within that display branch. Finally, manually assign a numeric “tabIndex” value for each accessible button to guarantee the order in which the buttons will be tabbed.

After setting accessibility properties and limiting tab order, you should be well on your way to having a decent accessibility presentation.

3) Synchronizing accessible and visual presentations.

Tabbing is great for an accessibility presentation, although it has the potential to get out of synch with the visual presentation (which is probably controlled by mouse clicks). So, it’s important to have both aspects of the presentation work together. This means that tabs need to simulate mouse clicks, and vice versa.

Simulating a mouse click to a button upon tabbing to it is easy. Just have the button listen for FocusEvent.FOCUS_IN, and have that trigger the button’s click action. Works like a charm.

Making a button obtain tab focus upon click is also  simple, given that Flash automatically gives focus to an object when its clicked. In the event that you need to manually give a button focus, use the “stage.focus” display property.

4) Forcing a screen reader to read an item.

In practice, the screen reader will read any new content that is set to the “stage.focus” property. So if you have a single object with changing content, you can trick a re-reading of the object by changing its accessibility properties, calling Accessibility.updateProperties(), and then nullify and reset the “stage.focus” property.

5) Buttons off stage don’t get read.

This was driving me nuts: I made a scrolling row of thumbnail images that you can flip through using the keyboard (tab/arrows). While flipping through thumbnails, the active thumbnail would slide into view if it was accessed outside of the scroll area. The solution worked great, visually. However, while Flash could tab to a button off of stage, JAWS wouldn’t read it. Once I deduced that stage bounds were the issue, I solved the problem by creating a second set of 1×1 pixel buttons hidden on stage that proxied the main buttons’ tab behavior. It seemed clunky, but it worked. However, it revealed another advantage: Flash has native support for intelligent arrow key controls based on tabEnabled buttons’ proximity to one another. When you line up a bunch of tabable button in a horizontal row, the left/right arrow keys are automatically set up to flip through them. Same goes for a vertical column: up/down arrow will be enabled for you. So, this tab proxy trick allows the tabEnabled buttons to be arranged in a horizontal or vertical fashion, regardless of the layout of the main visual buttons.

So, hopefully someone else will find this helpful. If any readers have other tips or tricks, please feel free to post them in comments!


Flint, Particles, and Animation Rendering

June 29, 2009

Sorry all for my abysmal rate of posts recently. To say the least, I’ve been busy with “A Stitch in Time” rolling into full development. However, that’s not to say that I don’t have material to post on – just lack of time to write about it.

However, I’ll take a sec here to cover one new area I’ve been getting heavily into: particle animation. For bigger, more complex animations like fire, smoke, and falling water, there is nothing quicker, easier, and better looking than a simple particle system. So, I’ve become a huge advocate of the Flint particle system. For those unfamiliar, Flint is an open-source particle engine built in AS3. It is super object-oriented, and may look a little intimidating at first if you’re not entirely comfortable with importing and instancing classes. However, you get the hang of it as you use it.

Flint makes some great animations. I set up a waterfall with a series of 6 particle emitters flowing down over an illustrated rock face, and it really looked beautiful. However, they also amounted to about 1200 particles – which proved to be a massive CPU hog. Ugh. Beautiful animation, but completely useless to my game world given that they’d cut the environment’s frame rate in half. So, I got thinking… how could I get the same animation without a performance hit?

The answer came from one of my own past blog posts about writing images out of flash. The post covers a script I had written to use the Adobe corelib’s PNG encoder to capture a display object as bitmap data and send to to PHP to be written. I was curious… would that work for “filming” a PNG sequence of a particle animation? 15 minutes later, I found the answer is – yes, it would.

The tool I built was simple: just snap a BitmapData image of a MovieClip on stage for X sequential frames, storing each frame in an array. Once X frames have been captured, encode each item in the array as a PNG and send it off to PHP to be written as a file. Now, that’s a pretty heavy burden on a network connection when you’re sending a sequence of 30+ PNG images off using URLLoaders. However, I tried the process running PHP locally on my Mac using MAMP, and it worked perfectly – with 1 second of 30FPS image capturing and less than a second of file writing, I had a folder full of pre-rendered particle animation frames. I did some post-production to make them loop, dropped the frames into a MovieClip, and stuck them into the game world. The waterfall looks fantastic, and there was no loss of performance.

The only downside to this solution is –obviously– filesize. Flint gave me a beautifully random animation for 16Kb. Pre-rendering gave me a beautiful 15-frame loop for 250Kb. This is certianly a compromise, and one that I would be very mindful of for larger animations intended for the web. However, in my circumstance I’m more focused on performance than filesize, so this worked for me. Hopefully, this may give other folks some ideas on routes to explore while optimizing animations.


Zoom and Pan Image Display

April 8, 2009

I’ve done enough zooming image displays recently that I formalized my code base into a class abstract. I thought I’d post it in case it’s useful to others.

The broad overview is that ZoomImage is a display container that acts as a mask for a child image. By calling the “zoomIn()” and “zoomOut()” methods,  the child image will zoom within the frame created by ZoomImage’s scrollRect. Once the image is zoomed in on, you can click and drag the zoomed image to pan it within the frame. ZoomImage takes care of all the math for zooming the image in and out of the center point of origin, and for restraining the image’s position to within the bounds of the frame.

This class does have one dependency on another code library: that being the awesome TweenLite AS3 library by GreenStock. If you’ve never used TweenLite before, then check it out. It’s extremely easy to use and is unbelievably handy! Just download and unpack TweenLite into your class library where ZoomImage can reference it.

Cheers!

ZoomImage.as

package
{
    import flash.display.Sprite;
    import flash.geom.Rectangle;
    import flash.events.MouseEvent;
    import gs.TweenLite;
    import gs.easing.*;

    /**
    * ZoomImage is a container for a zooming, panning image.
    * NOTE : this class has a dependency on the TweenLite AS3 library, available at:
    * http://blog.greensock.com/tweenliteas3/
    */
    public class ZoomImage extends Sprite
    {
        /** Minimum allowed scale value for the image. */
        public var minScale:Number = 1;

        /** Maximum allowed scale value for the image. */
        public var maxScale:Number = 4;

        /** The ammount that the image's scale is modified with each zoom in/out call.  */
        public var scaleIncrement:Number = 0.5;

        /** @private the cropped, zooming image. This MUST be a Sprite so that start/stop drag methods can be utilized. */
        private var _image:Sprite;

        public function ZoomImage($width:int=400, $height:int=300):void
        {
            super();
            scrollRect = new Rectangle(0, 0, $width, $height);
            addEventListener(MouseEvent.MOUSE_DOWN, this._onMousePress, false, 0, true);
            _image = _setImage();
        }

        /**
        * Creates the image asset (this can be customized as needed).
        * In this case, the demo image is being drawn as a vector.
        */
        private function _setImage():Sprite
        {
            // create an image display object.
            var $image:Sprite = new Sprite();

            // draw rectangle
            $image.graphics.beginFill(0xCCCCCC, 1);
            $image.graphics.drawRect(0, 0, displayWidth, displayHeight);
            $image.graphics.endFill();

            // draw circle
            $image.graphics.beginFill(0x999999, 1);
            $image.graphics.drawCircle(displayWidth/2, displayHeight/2, 30);
            $image.graphics.endFill();

            // draw X
            $image.graphics.lineStyle(1, 0x000000, 1);
            $image.graphics.moveTo(0, 0);
            $image.graphics.lineTo(displayWidth, displayHeight);
            $image.graphics.moveTo(0, displayHeight);
            $image.graphics.lineTo(displayWidth, 0);

            // add and return new image child.
            addChild($image);
            return $image;
        }

        /**
        * Specifies the width of the visible image area.
        */
        public function get displayWidth():int {
            return scrollRect.width;
        }

        /**
        * Specifies the height of the visible image area.
        */
        public function get displayHeight():int {
            return scrollRect.height;
        }

        /**
        * Zooms out from the image.
        */
        public function zoomIn():void {
            _zoom(1);
        }

        /**
        * Zooms in on the image.
        */
        public function zoomOut():void {
            _zoom(-1);
        }

        /**
        * @private
        * Zooms the image display.
        * @param $dir Direction of zoom, as expressed by a value of "1" (in) or "-1" (out)
        */
        private function _zoom($dir:Number):void
        {
            var $scale:Number = Math.max(minScale, Math.min(_image.scaleX + (scaleIncrement * $dir), maxScale));
            var $postW:int = (_image.width / _image.scaleX) * $scale;
            var $postH:int = (_image.height / _image.scaleY) * $scale;
            var $x:int = Math.min(0, Math.max(_image.x+((_image.width - $postW)/2), displayWidth-$postW));
            var $y:int = Math.min(0, Math.max(_image.y+((_image.height - $postH)/2), displayHeight-$postH));

            TweenLite.killTweensOf(_image);
            TweenLite.to(_image, 1, {scaleX:$scale, scaleY:$scale, x:$x, y:$y, ease:Strong.easeInOut});
        }

        /** @private called upon any mouseDown event on the image */
        function _onMousePress($event:MouseEvent):void {
            stage.addEventListener(MouseEvent.MOUSE_UP, this._onMouseRelease, false, 0, true);
            var $dx:int = _image.width - displayWidth;
            var $dy:int = _image.height - displayHeight;
            _image.startDrag(false, new Rectangle(-$dx, -$dy, $dx, $dy));
            cacheAsBitmap = true;
        }

        /** @private called upon any mouseUp event following a press on the image */
        function _onMouseRelease($event:MouseEvent):void {
            stage.removeEventListener(MouseEvent.MOUSE_UP, this._onMouseRelease);
            _image.stopDrag();
            cacheAsBitmap = false;
        }
    }
}

A Stitch In Time

April 1, 2009

Today I’m finally kicking off the PR campaign for my project of the year: A Stitch in Time, the long awaited sequel to Matthias Kempke’s What Makes You Tick?. This title has been a long time in the coming; and still has a long, difficult road of heavy development ahead. For those interested in the backstory thus far, I’ll catch you up on the details…

What Makes You Tick? launched in May of 2007. It was a pretty exciting release for me, given that it was the first complete end-to-end game built with the Lassie engine. Plus, Tick? was built by none other than my dear friend Matthias Kempke who I had met back in 2004 while touring Germany. During that visit I gave Matt the first-ever demo release of the Lassie engine. Matt was one of Lassie’s first independent developers, although he quietly built What Makes You Tick? behind closed doors on his side of the Atlantic… I never saw so much as a peep at his progress until the game was finished. That said, I had no idea that a Monkey Island whistling depiction of myself would make a cameo in Tick?, and –quite frankly– I nearly fell out of my chair when I played through and met “myself” for the first time… geeze, he even drew me wearing my complete backpacking attire from the 2004 trip. Spooky.

Now, while I didn’t get much of a sneak-peak at What Makes You Tick? before it was publicly released, I did at least get to see the original ending. If you’ve played the game, you probably know what happens: Whaamo! Fade to black… And originally, the game concluded with “To be continued”. I strongly urged Matt to remove the “To be continued” statement, given that it promised too much and almost undermined the weight of the cliff-hanger which was strangely satisfying in its own twisted way. He obliged, and I think we’ve delighted as many fans as we’ve “ticked off” with that decision.

Anywho, Matt and I met up again in the fall of 2007 to go hiking through the Swiss Alps. What Makes You Tick? had gained enough popularity in its six months since release to be called a success, and Matt was considering options for a new game concept using strong themes from Kafka literature. We batted some ideas around and ended up skidding sideways into a What Makes You Tick? connection that we both agreed really worked. After a few pints in an Interlaken pub one night, it was safe to say that the Kafka idea had taken the shape of a What Makes You Tick? sequel.

We chatted about this concept for over a year – proposing characters, places, and story elements; all in a pretty casual forum style that would need a lot more commitment before it went anywhere. While we generated a lot of ideas in 2008, we didn’t generate a whole lot of material. However, we were planning to meet up again in late 2008 so put Tick2 on the agenda of things to discuss.

We met up in September 2008 in Prague, Czech Republic which is –coincidentally and appropriately– the birthplace of Franz Kafka. The Prague summit faced the tough reality of where we are in our lives and that if we were ever going to do this, it had to be now. In some respects, it was an easy choice: the story had to be told. In others though, it’s difficult given that we do need to deviate from the roots of our hobbyist innocence. Big productions don’t happen without designated human resources, and human resources need to eat. Somewhere along the line the money factor enters the equation, which means moving away from indie gaming and into commercial production. And that’s a tough transition. No one wants to sell out; but you can’t produce real content without designated people who need to make a (meager) living. And the money prospect is particularly scary when you face the potential of bad sales turning into a lost investment. I guess we’ve managed to rationalize that a bit though: if our game sells, then we look forward to making additional titles in the future. If it flops… well, at least we got it out of our system in a BIG way.

Either way, we’re having fun producing the title. If players can have half as much fun playing it as we have designing it, then we’ve been (at least marginally) successful. Either way, we think that fans of What Makes You Tick? will find some interesting and exciting depth in A Stitch in Time’s story, even if we decide not to reveal what happens at the end of the first game… IF. ;-)


Public, internal, protected, and private

March 31, 2009

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.


Dynamic VU Meter Animation

March 23, 2009

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

March 4, 2009

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.


SoundSkin 1.0 – open source AS3 component

January 7, 2009

Following up my post from yesterday about easy sound control, I’ve continued expanding upon that class by adding in load management, percentage-based controls, and built-in mute/playback toggles. The class has become handy and robust enough that I’ve set up an official project page for it on Google code. So, SoundSkin is born, weighing in as a lightweight (1.5k) component. May it save many a developer from the headaches of “quick and dirty” sound implementation.

Full project source code, documentation, and a simple demo are available on the project’s Google code page: http://code.google.com/p/sound-skin/