explorers' club

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


3 Comments

Cool Find: Combining a Cairngorm-ish Command with Maté’s EventMap

So I am on the quest to create a hybrid MVC mini-framework that combines some of the best elements of Cairngorm, PureMVC and Maté.  The idea is to use the Command pattern from Cairngorm (because I like all my service/UX logic to be placed there and the EventMap’s dependencies on binding and MXML seem limiting), the Mediator pattern from PureMVC (which unclutters and decouples the views) and the EventMap and Injection logic from Maté (which will help to further decouple some of the command=>model logic).

Keep in mind I have only really been working with Maté for a couple of months and have only dived into actually understanding it in the last week or so.  So if you know of a better way of doing what I am trying to accomplish, please let me know and I can update the article.

This will mostly address how to decouple some of that command => model logic.  This means we are striving to get the command classes as model-agnostic as possible.  It also means there needs to be a slight modification to the current CairngormCommand structure.  We will keep the CairngormEvent in use because its data payload is useful in sending data back and forth from the event dispatchers/listeners.   In order for a command to send info back to a listener, it will need to extend EventDispatcher.  Then depending on the result or fault logic, it can dispatch an appropriate event with a data payload.  Here is some stub code:

public class SampleMateFriendlyCommand extends EventDispatcher implements IResponder
{
 public function execute (evt:Event):void
 {
    //the function signature could be anything including execute (... args)
    //notice I am not implementing the ICommand interface as I want to have more flexibility
 }

 public function result (data:Object):void
 {
   //parse data object if needed.

   var evt:CairngormEvent = new CairngormEvent("success");
   evt.data = parsedResultDataObject;
   dispatchEvent(evt);
 }

 public function fault (info:Object):void
 {
    //parse info object if needed.

    var evt:CairngormEvent = new CairngormEvent("fault");
    evt.data = parsedFaultInfoObject;
    dispatchEvent(evt);
 }
}

I like the Command pattern because I think of it in a military sense.  You issue a command to a soldier and that soldier executes the command, then generally reports back.  So this is akin to that analogy.  Next we need to see how to get the data back to the EventMap in order to wire the result/fault data into the appropriate places.  I tinkered with this for quite some time before stumbling upon this solution.  The Maté API docs are decent but fail to cover much beyond explaining the self explanatory.  I really hope they work on their API docs and really flesh out the information.

<mate:EventHandlers id="applicationCompleteHandler" type="{AppEvent.SAMPLE_MATE_COMMAND}" debug="true">
      <mate:AsyncCommandInvoker generator="{SampleMateFriendlyCommand}" successType="result">
           <mate:successHandlers>
                <mate:PropertySetter generator="{SomeModelObject}" targetKey="data" source="{scope.currentEvent.data}"/>
           </mate:successHandlers>
      </mate:AsyncCommandInvoker>
</mate:EventHandlers>

The AsyncCommandInvoker allows you to specify the event type that will trigger the successHandlers or the faultHandlers.  Accessing the data payload for the result or success event is done using scope.currentEvent.data.  Again I must reiterate that I stumbled upon this find because there was no documentation that I could find to support what I was trying to do.

The cool thing about this is that you have now freed up your commands so that they needn’t know about any specific model objects.  That is unless you really want to strongly type your result data objects.  This freedom allows for better testing as you can simply wire up a testing event map if you want to unit test.

Next up will be trying to wire mediators and their respective views into the event map.


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.


5 Comments

jwolib – new release 2008.12.15

A user of the lib brought to my attention a major flaw in my default styling setup.  This new release address the default styling as well as a few things regarding the TileCanvas’s itemRenderer (IFactory) generator class (now can use UIComponent, should implement IDataRenderer for best use).

jwolib 2008.12.15 (includes src, asdocs & SWC) – link


Leave a comment

as3isolib alpha 2008.11.03 new build released

This release addresses the issues associated with having a large number of scene items that might reside outside of the viewing area.  Also incorporated includeInLayout implementation for IsoContainer objects and renamed a few classes/APIs.

as3isolib home – link
as3isolib 2008.11.03 build – link


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);
}