# Can anyone explain step-by-step how the as3isolib depth-sorts isometric objects?

The library manages to depth-sort correctly, even when using items of non-1x1 sizes. I took a look through the code but it's a big project to go through line by line!

There are some questions about the process such as:

1. How are the x, y, z values of each object defined? Are they the center points of the objects or something else?
2. I noticed that the IBounds defines the bounds of the object. If you were to visualise a cuboid of 40, 40, 90 in size, where would each of the IBounds metrics be?

I would like to know how as3isolib achieves this although I would also be happy with a generalised pseudo-code version.

At present I have a system that works 90% of the time but in cases of objects that are along the same horizontal line, the depth is calculated as the same value.

The depth calculation currently works like this:

x = object horizontal center point y = object vertical center point

originX and Y = the origin point relative to the object so if you want the origin to be the center, the value would be originX = 0.5, originY = 0.5. If you wanted the origin to be vertical center, horizontal far right of the object it would be originX = 1.0, originY = 0.5. The origin adjusts the position that the object is transformed from.

AABB_width = The bounding box width. AABB_height = The bounding box height.

depth = x + (AABB_width * originX) + y + (AABB_height * originY) - z;

This generates the same depth for all objects along the same horizontal x.

• You actually need to know how as3isolib does this? Or you just want to know how it's done in general? What's the specific problem you're having? Other than not wanting to read source code. Please edit your question with updates. – MichaelHouse Jul 1 '12 at 15:52
• @Byte56 Updated with more detail. Thanks. – Rob Evans Jul 1 '12 at 20:00

Z-sorting or depth-sorting in as3isolib is calculated (by default) in the following class:

public class DefaultSceneLayoutRenderer implements ISceneLayoutRenderer


that can be found in:

package as3isolib.display.renderers


The code inside DefaultSceneLayoutRenderer itself is actually not too long (only 200 hundred lines of code w/comments and all) but quite clever. An outline of what it does is:

1 - Loop through all objects (children) in the scene, see what objects are behind child[i] (by looping again) and store them into an array or dictionary of dependencies. This is achieved in the following code:

public function renderScene (scene:IIsoScene):void
{

dependency = new Dictionary();

var children:Array = scene.displayListChildren;
var max:uint = children.length;

for (var i:uint = 0; i < max; ++i)
{
var behind:Array = [];

var objA:IsoDisplayObject =children[i];

var rightA:Number = objA.x + objA.width;
var frontA:Number = objA.y + objA.length;
var topA:Number = objA.z + objA.height;

for (var j:uint = 0; j < max; ++j)
{
var objB:IsoDisplayObject = children[j];

//skipped code for collision detection...

// See if B should go behind A
// simplest possible check, interpenetrations also count as "behind"
if (
(objB.x < rightA) &&
(objB.y < frontA) &&
(objB.z < topA) &&
(i !== j)
)
{
behind.push(objB);
}

}//end nested loop

dependency[objA] = behind;

}//end loop

//...
//see point 2


2 - Set the childrens' depth, using dependency ordering. Checking the dependency dictionary object, we place all the children that are inside it BEFORE ( = at a lower depth, thus they will be rendered behind) and we do this recursively to put each child's dependency list behind it. This is done here:

//reset depth between calls
depth = 0;

//visited is a dictionary of objects to make sure we don't add the same child twice
for each (var obj:IsoDisplayObject in children)
if (true !== visited[obj] )
place(obj);

// Clear out temporary dictionary
visited = new Dictionary();

}//end function renderScene

/**
* function place
* Dependency-ordered depth placement of the given objects and its dependencies.
*/
private function place(obj:IsoDisplayObject):void
{
visited[obj] = true;

for each(var inner:IsoDisplayObject in dependency[obj])
if(true !== visited[inner])
place(inner);

if (depth != obj.depth)
{
scene.setChildIndex(obj, depth);
}

++depth;
}


Note that this is naive z-sorting, so it's far from perfect. You can create your own class to "customize" z-sorting for your project using as3isolib, for that you'd only need to implement ISceneLayoutRenderer and assign it as your as3isolib scene layoutRenderer:

var myRenderer:CustomLayoutRenderer = new CustomLayoutRenderer();

scene.layoutRenderer = myRenderer;


Hope this helps!

• thanks that explains the process nicely. Regarding points 1 and 2 in the question do you know how the x, y, z values are related to the object? Is it object center or some other position? Thanks! – Rob Evans Sep 28 '12 at 11:00
• You're welcome! In order to get everything working properly, you need to have the origin point of your assets on a specific position - the top corner of the bottom face of the bounding box. This is easier to understand if seen graphically: check this as3isolib tutorial on assets and the IsoSprite class: code.google.com/p/as3isolib/wiki/as3isolib_tutorial_004 the last two images show graphically where the origin point should be on each case. – danii Oct 1 '12 at 10:30