explorers' club

explorations in dev, science, sci-fi, games, and other fun stuff!


5 Comments

Quick hint: Complex Component Development in MXML

Assume that you are creating a component in MXML such as some multi-state cell renderer or something that implements IDataRenderer.

All mx.core.Container subclasses have a convenient little event hook called dataChange.  Anytime you set a value to the data property, the component dispatches an event of type FlexEvent.DATA_CHANGE.  To hook into this you simple access it in MXML like so:

<mx:VBox dataChange="do something"/>

With this in mind I suggest that those wishing to do more complex visual changes to their component that {binding} cannot address do the following:

  • create a flag to indicate a data change has occured:
    private var bDataChange:Boolean = false;
  • connect the dataChange hook to the flag:
    <mx:VBox dataChange="bDataChange = true;"/>
  • address the data change in the call to update the display list:
    override protected function updateDisplayList (unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        if (bDataChange)
        {
            bDataChange = false;
            //do your custom logic here
         }
    }

The nice bit about this is that you are doing the necessary logic to update the display list when it makes sense to do so (via the already established update framework in the Flex API).  This will prevent many Null Pointer Exceptions (NPEs) due to a child component not being present when setting the component data from the overridden setter.  AND It also reduces the need to override the getter/setter for the data property in the first place.


1 Comment

Bitmap Fills oriented for Isometric Projection

Notes to self…

Given an image suitable for use as a bitmap fill, certain matrix transformations need to be done in order to orient the image to the xy, xz, and yz planes in the xyz octant.  Assume the following octant orientations:

myIso

Here are the following matrix tranformations:

  • XY plane orientation – this is the equivalent to rotating the image by 45º and then reducing the height by half the original scale.

    var m:Matrix = new Matrix();
    m.rotate(Math.PI / 4);
    var m2:Matrix = new Matrix();
    m2.scale(1, 0.5);
    m.concat(m2);

  • XZ plane orientation – this is simply skewing the image in the flash-based coordinate system along the  y axis.  Since most isometric projections (including the as3isolib) use a 2:1 ratio, we use Math.atan(0.5) rather than Math.PI / 6.

    var m:Matrix = new Matrix();
    m.b = Math.atan(0.5);

  • YZ plane orientation – same as the XZ plane however we use the skew value * -1;

    var m:Matrix = new Matrix();
    m.b = Math.atan(-0.5);


25 Comments

as3isolib alpha released

Yep its out there.  Yep its an alpha release which means that APIs, class names and basic project details are subject to change.  This release includes the source files, a SWC and docs.  I also added two of many tutorials to get people started.

as3isolib alpha release – link
as3isolib Google Code project page – link

Please feel free to send me questions, comments, criticisms, death threats, etc.  All input is welcome.

Thanks.
J


7 Comments

Absolute Isometric Depth Sorting

[update – 2010.01.27]

This should have been updated ages ago however I haven’t gotten around to it sorry 😦

A solution was found, check out the as3isolib’s DefaultSceneLayoutRenderer

[update – 20080909]

As I suspected, it was too good to be true.  More testing is necessary, however I feel I am on the right path.

[update – 20080908]

Finally did it!!!  Or at least it appears that I have accomplished my goals through initial testing phases.  I’ll restate those goals for clarity:

  • absolute isometric depth sorting – position & size determine depth without the aid of a tile based system.
  • objects residing at higher depths are still sorted by their intended visual placement including the possibility of appearing behind objects in the foreground whose heights may extend above the plane of the higher object.

Keep in mind this has only been tested against the case found in the previous updates where one object residing on a higher plane is tested against one object residing at a lower plane whose height is above the first object.  Further testing needs to take place in order to ensure this remains solid when multiple object are tested against one another.  Here is a quick rundown of a render phase:

  • container checks children for any size, depth, or geometry invalidation.  If so set a flag for further logic.
    • sort children by the following order:
      • elevation plane
      • isometric x value
      • isometric y value
    • if more than one elevation plane exists (simple check does children[0].z != children[children.length – 1].z), then we do a recursive manual sort by:
      • if A == B, continue
      • if A is intended to appear behind B (by performing a few simple position/geometry checks) then place B to A’s index + 1.
      • repeat loop
    • set each child’s depth to their index value within the sorted children.
  • call render on all children

[update – 20080907]

Ok so I made a big breakthrough.  I almost have it, I just need to refine the sorting algorithm just a tad bit more and it will be ready for a new round of testing.  Check out the screen shots (these are actual screen shots of the SWF, whereas the others from the earlier update were done using Sketchup):

The following 3 shots are obviously the good ones.  This test swf is animated with the blue box moving clockwise INSIDE the perimeter of the white boxes area and the orange box moving clockwise OUTSIDE the perimeter of the white boxes area.

Now here is the kink where I need to refine the sorting algorithm.  If the blue box’s screen y value is greater than the orange box’s screen y value, you don’t get the correct overlap.  Just a bit more tweaking and it should be good.

[update – 20080905]

After reaching out to a few contacts I thought I had made some progress.  Before I get started on this maybe I should post an image of what the problem is.  This is what I want to do:

Notice how the orange box is at a higher elevation than the gray boxes?  But using my current depth sorting algorithm the front-most gray box gets rendered behind the orange box like this:

My current algorithm slices up the scene based on elevations into an array.  The first array element would contain an array of all the gray boxes, the second element would contain an array with one element, the orange box.   Then I would sort both elements from front to back and order there depths recursively.  The issue with this sorting is that is still 2D depth sorting for a quasi 3D scene.

Any suggestions?

[update – 20080904]

So I kinda realized that this is great if you plan to not have stacked isometric objects.  In other words this works great if you are on a flat terrain map.  However this does not address issues with variable terrain (e.g. Diablo, Marble Madness).

I am still in the process of finding a smart, performance-friendly solution for this.  I am also thinking about setting a property on any container-type class that requires depth sorting to be able to use either the flat terrain approach (found here) or a variable terrain approach in order to maximize performance.

Thoughts?

[original post]

Recently I have been working on my Flash-oriented projects.  Specifically I started working again on isolib, an AS3 isometric library.

Used to in AS2 you could delegate the task of depth sorting to the flash player by doing some calculations and assingning a number without regards to wether or not a depth preceeding it was filled.  For example, I have 5 Sprites.  In AS2 you could assing Sprite #1 to depth 0, Sprite#2 to depth 50 and the other 3 Sprites could have arbitrary numbers assigned to them.  The flash player took on the task of ordering the display list for you.  In AS3 that is not the case as you will run into Run Time Errors if you try to assing a DisplayObject to a depth without the prior depths being occupied.  So now the task is assigned to the developer.

Now as many ways as there are to skin a cat, there are as many ways to do isometric depth sorting.  Almost all that I have found utilize tile-based algorithms.  Though they work with respect to tile-based applications, they don’t seem to do that great for absolute positioning.

Anyway to cut to the fat here is how I achieved Absolute Isometric Depth Sorting without the need to have tile-based logic assigned.  Before I jump in tho, my coordinate space is somewhat diffenent than that of traditional isometric coordinate spaces: x values go from the top-left to the bottom-right portion of your screen, y values go from the bottom-left to the top-right portion of your screen and z values go from bottom to top of your screen.  Make sense?  Okay, let’s go:

Almost any renderable element in my iso-world has to have x, y, z, width, length, and height depending on how many dimensions they occupy (2 vs 3 dimensions is like comparing a plane to a cube).  Let’s assume we are dealing with a cube.  Now since we the viewer represent the vantage point, I created a reference point to compare distances to which resides at x:100000, y:100000 and z:100000 (hopefully we will not exceed any points outside of that).  My sorting method simply compares distances from the right-front-most point of an object from the reference point.  That point is basically x:cube.x + cube.width, y:cube.y + cube.length, z:cube.z Now this is not fail safe but it does a good job in absolute coordinate spaces.

Obviously there is some more robust logic occurring in my IsoScene class in order to depth-sort but this is the basis for the sort.  Check out the demo app here – link

override public function render (recursive:Boolean=true):void
{
	var depthArray:Array = [];
	var infoObj:Object = {};

	var child:IPrimitive;
	for each (child in children)
	{
		infoObj = {};
		infoObj.child = child;
		infoObj.distance = Math.sqrt((camera.x - child.right) * (camera.x - child.right) +
			(camera.y - child.front) * (camera.y - child.front) +
			(camera.z - child.z) * (camera.z - child.z)) * -1;

		depthArray.push(infoObj);
	}

	depthArray = depthArray.sortOn(["distance", "x", "y", "z",], Array.NUMERIC);

	var i:int;
	for each (infoObj in depthArray)
	{
		if (infoObj.depth != i && (infoObj.child.positionInvalidated || infoObj.child.geometryInvalidated))
			setChildIndex(infoObj.child, i);

		i++;
	}

	super.render(recursive);
}


6 Comments

Life of a UIComponent

[UPDATE 2011.01.19]

Since the release of Flex 4 and the Spark framework, quite a lot has changed in the component life cycle.  Not that this logic has been removed, it has just been added to to accommodate the new Spark framework.  Hopefully I will find some time to update this or make a new post.

Reality Check

I have been developing in Flash for more years than I can remember and Flex since its inception.  Its amazing how with that many years under my belt, a professional title of “Sr. Flex Consultant” and a pretty good comprehension of the “engine” of AS3, I still don’t know some basic things.

Case in point:

I was browsing Kirupa’s AS3 forums to see if I could swing in and make someone’s day by solving their AS3 woes.  I found a guy who was basically trying to access child DisplayObjects on a DisplayObjectContainer from within the parent’s constructor.  Now I don’t know if he was trying to access children instantiated programmatically or those placed on the timeline (I assume the latter case), but the problem is a result of the child references being null during the constructor.  Seems like an easy solution right?  Just wait and then do a check then any subsequent logic if applicable, else wait some more.

I wanted to provide the guy some insight and so I thought, “you know a UIComponent is pretty damn straight forward”.  It even has a great method called childrenCreated that you can leverage.  But trying to find a solution from a UIComponent is quite difficult because the process isn’t as straight forward as I had assumed it to be.  I was amazed to realize that I hadn’t the clear understanding of what goes on under the hood of the MX framework as I had previously thought.  Anyway, to make a not so long story short, I present a detailed look into the life of a UIComponent.  BTW – all of this material can be found in the API docs as well as snooping around the MX code base.

Life of a UIComponent

Birth

  1. instantiation (aka. the constructor) – so there are a few differences when instantiating programmatically vs. declaritively (via MXML).  For now let’s make the assumption that we are dealing with programmatic instantiation.  The UIComponent doesn’t belong to the displayList, it is simply an object in memory.
  2. configuration – this may happen in the constructor or it may happen immediately after the UIC is created, but most properties needing initialization are set here as well as event handlers and other logic.  Keep in mind that some properties that are actual getters/setters can flag the UIC for invalidation/validation logic.
  3. adding to the displayList – in order to be a useful UIC, it needs to be brought into the fold.  So a parent UIC adds it to its displayList node.  Interestingly, the addng of a UIC to the displayList causes a lot of under-the-hood logic to take place.  For this section, the UIC in question is the one being added, not the parent.
    1. any former parent reference is removed (via DisplayObjectContainer(formerParent).removeChild(this))
    2. the UIC has some initialization performed on it regarding its document properties, styling, and some Module logic with regards to its new position within the displayList.
    3. the UIC is actaully added into the displayList.  This is done at a lower level withing the Flash player.  Doing so triggers an Event.ADDED event which is captured by the UIC’s parent.  This event is delayed and redispatched at a later point.
    4. the UIC’s initialize() method is called which drills down yet another chain of events:
  4. initialization – the UIC’s initialize() method is called which drills down yet another logic chain.  Note the possible recursive nature of this logic:
    1. the FlexEvent.PREINITIALIZE event is dispatched
    2. createChildren() is called
    3. childrenCreated() is called which trigger the invalidateProperties, …Size() and ..DisplayLIst() methods.  Note that the UIC may have been flagged for invalidation in step #2 (the configuration phase)
    4. accesssibilities are initialized
    5. the FlexEvent.INITIALIZE event is dispatched

Life within the display list

Up till now, the life of our UIC has been pretty easy to follow.  It and it’s parent have done quite a bit during the birthing process.  But now that the UIC has been flagged for invalidation, it gets a bit blurry.

  1. invalidation – most of the getters/setters in a UIComponent have some logic that says, “if the new value doesn’t = the old” then it is to invalidate the properties, size and/or displayList.  Most folks who do any component development make a great deal of use of these invalidation methods.  Most folks (like me) probably had assumed their wasn’t any logic that took place betw. invalidation and validation processes.  Oh but there is.An invalidation method is quite simple, it check two things, does the UIC (UIComponent hereinafter) have a parent and has a global-level ILayoutManager exist.  If both conditions are met, then the UIC hands itself over (as a parameter) to the ILayoutManager.   By doing these two checks a Flex app can conserve processing resources in case the UIC doesn’t reside within the displayList.  Why update something that isn’t visible to the user?  It does get updated, it just doesn’t get validated.
  2. managing the layout – Even though the name implies just layout-related tasks, the LayoutManager handles task related to invalidateProperties, invalidateSize and invalidateDisplayList.  By a system of boolean flags and queues, the LayoutManager goes thru the 3 pre-validation phases of telling each UIC in its queue.  Does UIC#2241782 need its size or properties validated?  Does UIC#99892 need to update its display list?  This kind of logic takes place here.  The queing mechanisms are complex and recursive so I won’t go into detail here, but suffice it to say works alot like a short-order cook.The really interesting thing about the LayoutManager is that it is main engine that drives the MX framework.  If any of you were ol’ Flash dev’rs and remember having to do onEnterFrame logic, this kind of logic is presented here but in very tricky fashion.  LayoutManager actually has a UIC that doesn’t reside in the display list.   This UIC is called the callLaterObject and as you can guess is used as the work horse for leveraging the ENTER_FRAME and RENDER events that get triggered.  At each triggering, the callLaterObject then reports back to the LayoutManager that we are in the next frame so we can now start the validation process on our queued UICs.
  3. validation – now that we have a new frame to work with, the LayoutManager will goto its needs-validation-queue and grab each UIC and issue validation orders.  Once that is done, the UIC in question gets added to yet another queue and a series of checks takes place before starting all over again for the next round of invalidation requests.

Summary

With the sort of logic that takes place for a mutltitude of UIComponents within an app, the geniuses over at Adobe have come up with a highly efficient system for managing resources while making the updates.  I hope this provides some insight.  And also sound off if you find that I am in error in writing this, as this was a journey of discovery for me as well.

J


4 Comments

Normalizing Value Objects: Quick Tip

A buddy of mine asked me the other day if I had any thoughts on normalizing value objects coming in from various services.  For example say you have at least 3 different objects that all share similar properties but aren’t quite named the same thing for convenience sake.  Let’s assume that your service guy is simply assembling objects straight from the database table and using their column names rather than normalizing it for you.  Here are the sample objects:

ArtistObject
{
     artistName:String
     artistId:int
     artistGenres:Array
}

AlbumObject
{
     albumName:String
     albumId:int
     albumGenres:Array
}

TrackObject
{
     trackName:String
     trackId:int
     trackGenres:Array
}

And let’s say you want to normalize those incoming objects to an interface like so:

IMediaObject
{
     name:String
     id:int
     genres:Array
}

Your first inclination may be to use an else..if statement to cycle thru the variou value object types that may be expected in a given response (assuming you are not doing low-level CRUD services and are actually leveraging services for various purposes) like so:

if (vo is ArtistObject)
{ ... }
else if (vo is AlbumObject)
{ ... }
else if (vo is TrackObject)
{ ... }
else if .... you get the point

Here is an often overlooked but extremely useful operation that will eliminate lengthy else..if loops while allowing you to cycle thru known properties to retrieve non-normalized property values.

var targetObject:IMediaObject = //whatever you are normalizing to
var vo:Object = serviceResponse.data //the object returned from your service
for (var s:String in vo)
{
   //we are going to check each prop name to see if there is a match for our
   //targetObject's known properties
   //obviously this list will grow the more props you have to normalize
   //however it only grows once regardless of the number of non-normalized VOs
   if (s.toLowerCase().indexOf('name') != -1)
      targetObject.name = String(vo[s]);

   if (s.toLowerCase().indexOf('id') != -1)
      targetObject.id = int(vo[s]);

   if (s.lowerCase().indexOf('genres') != -1)
      targetObject.genres = vo[s] as Array;
}


6 Comments

Tutorial: AppCoreLib’s XMLDataBroker, mock XML data & Cairngorm

The potential of Flex for rapid prototyping and general application development is amazingly fast. With some mock data and a basic user-experience (UX) scenario, a developer can create a functioning sample application in a matter of minutes.

If you are developing either a full blown RIA or a prototype application then you have probably at least heard of Cairngorm. If not, familiarize yourself with the basics here – link. I use a stripped down version of it for almost every project I have worked on. It works beautifully

I plan to show you an example of using AppCoreLib‘s XMLDataBroker to fill in some mock XML data for your commands. This is helpful when you have a basic idea of an API/services but they are not returning anything or not ready to be tapped or you wanna test out a service’s result format before the server developers implement it.

Before I continue, let’s set one or two rules about this tutorial.

  • the expected format for the returned data is XML
  • the mock XML data format will reflect the same format of the actual service’s result

Firstly let’s take a look at a basic Cairngorm command. This is a stripped down version so you won’t see any delegate-type references in here.

package com.foo.controller.commands
{
    import com.adobe.cairngorm.commands.ICommand;
    import com.adobe.cairngorm.control.CairngormEvent;
    import com.foo.business.Services;

    import mx.rpc.AsyncToken;
    import mx.rpc.IResponder;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.http.HTTPService;

    public class SampleCairngormCommand implements ICommand, IResponder
    {
        private var _vo:Object = {};

        public function execute (event:CairngormEvent):void
        {
            var call:HTTPService = Services.getInstance().httpService;
            call.url = "http://www.foo.com/someService";

            var param:Object = {};

            var token:AsyncToken = call.send(param);
            token.addResponder(this);
        }

        public function result (data:Object):void
        {
            var xmlResult:XML = ResultEvent(data).result as XML;
        }

        public function fault (info:Object):void
        {
        }

    }
}

So now with about 5 lines of code, I will show you how to inject mock XML data for creating a response that fits within the Cairngorm command structure:

package com.foo.controller.commands
{
    import appCoreLib.business.XMLDataBroker;
    import appCoreLib.events.XMLLoadEvent;

    import com.adobe.cairngorm.commands.ICommand;
    import com.adobe.cairngorm.control.CairngormEvent;

    import mx.rpc.IResponder;

    public class SampleCairngormCommand implements ICommand, IResponder
    {
        public function execute (event:CairngormEvent):void
        {
            var x:XMLDataBroker = new XMLDataBroker();
            x.addEventListener(XMLLoadEvent.XML_LOAD_SUCCESS, result);
            x.addEventListener(XMLLoadEvent.XML_LOAD_FAILURE, fault);
            x.loadXML("assets/xml/someMockXMLData.xml");

            /* var call:HTTPService = Services.getInstance().httpService;
            call.url = "http://www.foo.com/someService";

            var param:Object = {};

            var token:AsyncToken = call.send(param);
            token.addResponder(this); */
        }

        public function result (data:Object):void
        {
            var xmlResult:XML = XMLLoadEvent(data).xml;
            //var xmlResult:XML = ResultEvent(data).result as XML;
        }

        public function fault (info:Object):void
        {
        }
    }
}

That’s it! Simple, effective and most importantly, easy to remove once an actual service response is available.


8 Comments

Tutorial: handling service validation errors & cairngorm – part 3

recap

Last time we discussed two methods for handling service validation errors in a Cairngorm application. The first method was to borrow from some AS2/ARP techniques by passing a reference. The second method was to leverage the event nature of Flex and use a central event dispatcher type approach. Both of these have their advantages and certainly have their disadvantages. This last approach will try to take the best from both worlds and combine them to alleviate some of the problems we encountered.

ServiceValidationErrorManager method

Again you will have to pardon the names here but this gets the point across. There is no doubt what this puppy does. For the sake of simplicity I will continue to call it “the manager”. Ok so the manager is a) a Singleton-type class and b) has at its root a property called currentClient. Here’s a peek:

pacakge com.foo.managers
{
     public class ServiceValidationErrorManager
     {
         public var currentClient:IServiceValidationClient;
         static private var _instance:ServiceValidationErrorManager;
         static public function getInstance (){}//you get the idea....
     }
}

The idea is pretty much the same as the first method in that our views serve as the IServiceValidationClient. When dispatching a Cairngorm event we register the client with the manager class (if applicable). Basically that is achieved by:

ServiceValidationErrorManager.getInstance().currentClient = this; //the view/implementor

So this fixes issues from the other two methods. Firstly it eliminates the need to pass the view to the command. Secondly it doesn’t get us tangled up in all these IEventDispatcher methods.

Now upon a response that has some validation errors, we can simply say:

ServiceValidationErrorManager.getInstance().currentClient.handleValidationErrors();

The other nice thing is that we needn’t really worry about garbage collection because we’re only dealing with one property on one class. It gets overwritten when needed. Now you may be asking why use a separate manager type class. Well you may want to have some logic in there for various things including queuing the views, and other crap I can’t think of right now.

summary

This could easily be adapted to a preexisting singleton model so you can reduce the need for the additional class. You just gotta remember its there. Also, even though you needn’t clear out the property on the manager, it does make good practice. Having a manager class allows you to do just that: manage validation errors appropriately. Of course this might be a grotesque oversimplification of a very serious need, you get the gist of the idea.

pros:

  • OOP
  • negates the use of IEventDispatcher logic in both view and command
  • provides a centralized place to handle more robust registration for error handling

cons:

  • adds another class
  • still doesn’t address timing issue, unless you implement some queuing mechanism in the manager when setting the current client
  • not as elegantly simple as method one

That’s it folks. 3 very ugly solutions to an ugly problem. Chime in and let me know how you do it. Thanks.