Game Development Community

Setting layer order based on Y-Axis

by Daniel Stirk · in Torque Game Builder · 12/05/2005 (2:58 pm) · 11 replies

A lot of people are trying to script RPGs, and one of the main problems is getting the sprites to appear above and below eachother in a semi-isometric view. The best and fastest way to solve this is to edit teh source to change the rendering order based on the Y-Axis. TO do this, you must edit the source, and you will sacrifice any Z-Order control in the script. You will have to use other layers to have things above or below each other all the time.

I have only used this in 1.0.2 so far. Have not tested with the new Alpha release!

Scroll down to get Torque2D 1.1 ALPHA Version Code with optional fixes

-------------------------------------------------------------------------
To do this, Open your T2d.sln file and follow these instructions.
-------------------------------------------------------------------------
Open the file named fxSceneGraph2D.h

Find around line 189 the following code:

static S32 QSORT_CALLBACK layeredRenderSort(const void* a, const void* b);
and add after it
tatic S32 QSORT_CALLBACK layeredIsometricSort(const void* a, const void* b);


Next, open the file fxSceneGraph2D.cc

Find around line 293 the following code:

S32 QSORT_CALLBACK fxSceneGraph2D::layeredRenderSort(const void* a, const void* b)
{
	// Layer-Order Sort.
	return ((*((fxSceneObject2D**)a))->mLayerOrder) - ((*((fxSceneObject2D**)b))->mLayerOrder);
}
and add in after it
S32 QSORT_CALLBACK fxSceneGraph2D::layeredIsometricSort(const void* a, const void* b)
{
	// Layer-Order Sort.
	return ((*((fxSceneObject2D**)a))->getPosition().mY) - ((*((fxSceneObject2D**)b))->getPosition().mY);
}

Last, in the same file, find around line 2685 the code:

pDebugStats->objectsLayerSorted += layerSize;
}
And add after those lines (outside the if statement!)
dQsort(mLayeredRenderList[layer].address(), layerSize, sizeof(fxSceneObject2D*), layeredIsometricSort);



This is just a quick fix for a Y-Axis Z-Ordering format. Useful for RPG sprites that appear behind or in front of each other.

#1
12/05/2005 (11:44 pm)
Nice one Daniel. This should work without problems in the alpha as well (with minor naming changes).

- Melv.
#2
12/07/2005 (6:36 am)
This for some reason, changes the tile editor so that the layers are reversed. Instead of Layer 0 being on teh bottom, it's on the top. It's probably because it's all on one layer, which is reordered this way. I'll add a flag into the code so it's optional to turn on in script.

I'll do this when I convert to 1.1. So, if you use this, the way your layers show in the tile editor will be reversed.

Tourque2D 1.1 APLHA Version

This is the new way to do layer ordering for sprites. It orders layers by the Y-Axis, and only does it if the scenegraph is set to do it.

Works only with the new Torque2D 1.1 APLHA release

---------------------------------------------------------------------------------
Open T2d.sln file and follow these instructions.
---------------------------------------------------------------------------------

Open the file named t2dSceneGraph.h


Find around line 149 the following code:

CDebugStats                 mDebugStats;
and add after it
bool                 mIsometricLayering;

Find around line 199 the following code:

static S32 QSORT_CALLBACK layeredRenderSort(const void* a, const void* b);
and add after it
tatic S32 QSORT_CALLBACK layeredIsometricSort(const void* a, const void* b);

Find around line 300 the following code:

bool    setSceneDrawOrder( t2dSceneObject* pSceneObject2D, eDrawOrderCommand command );
and add after it
void	setIsometricLayering( bool status );


Next, open the file t2dSceneGraph.cc

Find around line 282 the following code:

mSceneGraphInitialised(false)
and REPLACE this with:
mSceneGraphInitialised(false),
mIsometricLayering(false)

Find around line 305 the following code:

S32 QSORT_CALLBACK t2dSceneGraph::layeredRenderSort(const void* a, const void* b)
{
	// Layer-Order Sort.
	return ((*((t2dSceneObject**)a))->mLayerOrder) - ((*((t2dSceneObject**)b))->mLayerOrder);
}
and add in after it
S32 QSORT_CALLBACK t2dSceneObject::layeredIsometricSort(const void* a, const void* b)
{
	// Layer-Order Sort.
	return ((*((t2dSceneObject**)a))->getPosition().mY) - ((*((t2dSceneObject**)b))->getPosition().mY);
}

Find around line 1045 the following code:

return objectMoved;
}
and add after it (outside the brackets)
//-----------------------------------------------------------------------------
// Set Isometric Layering Status.
//-----------------------------------------------------------------------------
ConsoleMethod(t2dSceneGraph, setIsometricLayering, void, 3, 3, "(status) - Set automatic isometric layering status.")
{
    // Set Isometric Layering Status.
    object->setIsometricLayering( dAtob(argv[2]) );
}
void t2dSceneGraph::setIsometricLayering( bool status )
{
    // Set Isometric Layering Status.
    mIsometricLayering = status;
}

Last, in the same file, find around line 2685 the code:

pDebugStats->objectsLayerSorted += layerSize;
}
And add after those lines (outside the if statement!)
if ( mIsometricLayering )
dQsort(mLayeredRenderList[layer].address(), layerSize, sizeof(t2dSceneObject*), layeredIsometricSort);

It defaults to no isometric sorting. To activate it (at any time) use this code:

scenegraphname.setIsometricLayering(true);

Alternatively, you could use false

Works very well and very smoothly
#3
01/03/2006 (9:44 pm)
Updated this to work for Torque2D 1.1 Alpha. Post back it you have any problems getting it to work or compile. Any suggestions would be great as well.
#4
01/04/2006 (12:05 pm)
Very cool... I really want to test this once I get a chance :)
#5
01/10/2006 (12:41 am)
The only problem with it is if you use this with a lot of different size sprites, it's gonna mess up. If you have a sprite with a height of 20 and one with a height of 10, then the center points are going to be off and you'll have the wrong one in front if you are using teh bottom of the sprite as a base (like the feet of a character).

I probably should have done it to measure where the bottom of the sprite is. If anyone wants me to modify it to work like that, I can. I myself use sprites of similar size, and the collision at their bases offsets minor height changes.
#6
01/10/2006 (10:17 am)
I am really interested in this as well.

So sprites on the same layer will be rendered with the sprite having the lesser Y coordinate in front?

- Jesse
#7
01/10/2006 (11:57 am)
I am really interested in this as well.

So sprites on the same layer will be rendered with the sprite having the lesser Y coordinate in front?

- Jesse
#8
01/10/2006 (12:03 pm)
If you take the Strategy Tut I'm finishing up in the next day or two and apply this to it you should have a very good foundation for a Strategy game :) (right now mine is just top down, though no reason you co uldn't apply this and do ISO art to get a real ISO Strategy game look and feel).
#9
01/10/2006 (3:56 pm)
@Jesse
Correct. Anything with a center point below the other will be rendered in front on the same layer. Again, it's the center point right now and not the base of the sprite. I'll have time to work on it later this week. Shouldn't bee too difficult to add in half the height.
#10
01/10/2006 (3:58 pm)
Very cool!

Thanks Daniel
#11
01/20/2006 (6:20 pm)
If you guys want this to do the isometric sorting by the bottom of the sprite and not the center, replace the code you added at line 305 with this. It will take the centerpoint and add half the height to sort by the bottom of the sprite.

S32 QSORT_CALLBACK t2dSceneGraph::layeredIsometricSort(const void* a, const void* b)
{
	// Layer-Order Sort.
	return ((*((t2dSceneObject**)a))->getPosition().mY + ((*((t2dSceneObject**)a))->getSize().mY / 2.0) - ((*((t2dSceneObject**)b))->getPosition().mY + ((*((t2dSceneObject**)b))->getSize().mY / 2.0)));
}