Bug Report: Sprite Sorting

Hey dyson,

I’ve found a bug in the sprite sorting algorithm. Details and (simple) fix follow.

Thanks.

= = = = = = = = = =

MTE 0v957

DESCRIPTION:

Error occurs when sprite sorting is enabled.

ERROR:

mte.lua:13189: attempt to perform arithmetic on field '?' (a nil value)

FIX:

Line 13183, add :

[lua]local i = object.layer; local i2 = i[/lua]

Hi dyson,

Sprite sorting works great but I’ve now run in to another problem, which I can’t easily fix, and I’m hoping you can help.

My app is a top-down / RPG style game where the hero is 1 tile wide, 1.5 tiles tall (levelWidth = 32, levelHeight = 48, offsetY = -18, to be precise).

I’ve programmatically created and added sprites to the map at once (let’s say coins to be collected) and then created and added the hero last. Everything is fine with the sorting - in that coins located in the rows above him appear behind him - but I have an issue with the sprites when he comes to occupy the exact same tile space as them: he arbitrarily appears directly in front or behind the item but never consistently one or the othe. Ideally I’d like him standing behind each one before it’s collected as he’ll also be collecting/dropping inventory during the game too and the player will need to be able to see what they’re standing on.

Am I missing something? Is it possible to sort the order of sprites on a given tile?

Thanks again!

Hello AppDeveloperGuy,

Thanks for reporting that bug, it snuck right past when going from 0v956 to 0v957! I’ll release a new minor update this week including the fix.

You can try a few things to address the sprite sorting issue you’re having. The easiest might be to use the player sprite’s toFront() or toBack() method in your enterFrame event. Say you have a coin at 1,2 and a coin at 1,3, and the player is also at 1,3. Calling player:toBack() each frame would move the player behind the coin at 1,3. The coin at 1,2 is in a seperate display group behind the player and the other coin, so calling player:toBack() won’t move the player behind the coin at 1,2. The player will still correctly appear in front of objects behind it on the map, but it will always display behind objects in the same plane.

You can also increase the resolution of the sprite sorting algorithm. By default the map is split into as many sprite sort display groups as there are Y locations. A map 100 tiles tall will have 100 possible depth positions. Setting mte.spriteSortResolution = 2 will double the number of depth positions. Each Y position will contain two possible depth positions, so an object in the top half of a tile will fall behind an object in the bottom half of a tile. I recommend using whole numbers for mte.spriteSortResolution. Increasing mte.spriteSortResolution may impact map load times as the engine generates the needed sprite sort display groups.

Thanks dyson. I had tried toFront() and toBack() in the game loop but still no joy. Fortunately I’ve just this moment realised my error: I was calling it in the movement checking block, which occurs before mte.update(), and of course it was being immediately undone during MTE’s sorting. Now I check for movement again after mte.update() - with a simple boolean flag set from before - and call it there and hey presto!

Thanks again for the quick reply.

Hi dyson,

Sprite sorting works great but I’ve now run in to another problem, which I can’t easily fix, and I’m hoping you can help.

My app is a top-down / RPG style game where the hero is 1 tile wide, 1.5 tiles tall (levelWidth = 32, levelHeight = 48, offsetY = -18, to be precise).

I’ve programmatically created and added sprites to the map at once (let’s say coins to be collected) and then created and added the hero last. Everything is fine with the sorting - in that coins located in the rows above him appear behind him - but I have an issue with the sprites when he comes to occupy the exact same tile space as them: he arbitrarily appears directly in front or behind the item but never consistently one or the othe. Ideally I’d like him standing behind each one before it’s collected as he’ll also be collecting/dropping inventory during the game too and the player will need to be able to see what they’re standing on.

Am I missing something? Is it possible to sort the order of sprites on a given tile?

Thanks again!

Hello AppDeveloperGuy,

Thanks for reporting that bug, it snuck right past when going from 0v956 to 0v957! I’ll release a new minor update this week including the fix.

You can try a few things to address the sprite sorting issue you’re having. The easiest might be to use the player sprite’s toFront() or toBack() method in your enterFrame event. Say you have a coin at 1,2 and a coin at 1,3, and the player is also at 1,3. Calling player:toBack() each frame would move the player behind the coin at 1,3. The coin at 1,2 is in a seperate display group behind the player and the other coin, so calling player:toBack() won’t move the player behind the coin at 1,2. The player will still correctly appear in front of objects behind it on the map, but it will always display behind objects in the same plane.

You can also increase the resolution of the sprite sorting algorithm. By default the map is split into as many sprite sort display groups as there are Y locations. A map 100 tiles tall will have 100 possible depth positions. Setting mte.spriteSortResolution = 2 will double the number of depth positions. Each Y position will contain two possible depth positions, so an object in the top half of a tile will fall behind an object in the bottom half of a tile. I recommend using whole numbers for mte.spriteSortResolution. Increasing mte.spriteSortResolution may impact map load times as the engine generates the needed sprite sort display groups.

Thanks dyson. I had tried toFront() and toBack() in the game loop but still no joy. Fortunately I’ve just this moment realised my error: I was calling it in the movement checking block, which occurs before mte.update(), and of course it was being immediately undone during MTE’s sorting. Now I check for movement again after mte.update() - with a simple boolean flag set from before - and call it there and hey presto!

Thanks again for the quick reply.