MTE and Display Groups

Hoping somebody might be able to offer some advice on the following.

I have a tilemap comprising of three tile layers, which represents the main game environment/world.

In addition I have a display group hierarchy that covers:

The World - I insert MTE in to this group (the above three tile layers) plus sprites/images that are added as the game progresses, i.e players build an item/building.

Maps Display Group - a “heatmap”, visually representing the properties (value, …) of each individual tile.

HUD Display Group - UI elements

I’m creating the HeatMap by creating blocks (display.newRect) and adjusting their colour values dependant upon the property value - essentially it’s just a layer above the game map that clones its structure. I had issues with moving/dragging the camera/map and scaleFactors so decided to add these “blocks” via mte.addSprite and let MTE handle them.

All works as expected, however I’m struggling to organise the various components into the display group hierarchy  that I’ve planned. Currently when tggling the heatMap on/off I run through the .numChildren of that particular displayGroup - but if I don’t add them to this I have no way (to my knowledge) of performing this action.

I haven’t experimented much with MTE and different display groups, I’ve noticed mte.setParentGroup() however that doesn’t appear to solve my issue. Essentially I want MTE to have control over the various visual components but at the same time squeeze these into the display groups that I’ve created for organisational purposes.

If I add the “block” into my display group after using addSprite I notice that the heatmap layer won’t move with the map drag/movement - as expected considering it’s out of MTE’s control now I guess.

To be honest I’m struggling to explain the problem I’m facing, but would appreciate if somebody could confirm that MTE works nicely with manually created display groups and perhaps a prod in the right direction.

Many thanks…

I use groups with no problem, but I didn’t try to put the mte map in a group.

I create my groups after the command mte.loadMap(). 

mte.loadMap("level01.json") local grpHud = display.newGroup()  

If I understand you correctly, you’re creating colored rectangles and adding them to an MTE map layer using addSprite(), and then you are adding them to a custom display group you’ve created for organizational purposes. Adding them to your custom group removes them from MTE’s map layer group. I think the underlying cause here is that Corona SDK will not allow a display object to be a child of two display groups simultaneously. If you add a child of one group to another group, the child will be removed from the first group.

My recommendation is to create a sprite layer(s) on the map above all the other map layers and use this layer group for your heat map display. Being a map layer, it will move and respond to camera control as the others do. You can retrieve the layer’s group object with mte.getLayerObj(), or you can retrieve the map object with “local myMapObj = met.getMapObj()” and reference the desired group by index (myMapObj[1] is the first layer group in the map, myMapObj[#myMapObj] is the last). You can then loop through the group’s children as you like. You can also simply set the group object’s alpha to show or hide it.

Taking this even further, it would be better if the heatMap were a tile layer and the rectangles tiles, because these tiles would then be spawned and culled as you moved the camera. Without this culling (depending on the size of your map) you could end up with an excessively large number of display objects as the player moved the camera around.

Dyson - as always, thanks for your input. That’s exactly the problem and one that I was aware of (Corona moving display objects when changing groups), but unsure as to the best way to overcome this obstacle.

Your suggestion sounds perfect; can I just ask a followup:

You mention it would be preferable to have these as tiles due to culling, which I understand - however I run the following calculation to work out the colour that the tile in the heatmap should be:

[lua]

local waterValue = (self.m_GridArray.tileProperties[child.tileX][child.tileY].waterLevel * 2.55) / 255

print("Child TileX: "…child.tileX)

print("Child TileY: "…child.tileY)

print("Water Value: "…waterValue)

child:setFillColor(0, 0, waterValue, 1)

[/lua]

This allows me to adjust the colour based on a watervalue of 0-100 (and using G2.0 's 0:1 range).

Presumably I could just use a whole bunch of white tiles in a tile layer and adjust the colour accordingly???

Yes, using white tiles and adjusting their color would be best I think. You could also then use the same tiles to display different data and even combine different data sets together for each tile, like displaying an overall growth suitability factor or something of the like. Tile display objects store their associated map location in .locX and .locY, as well as other useful information.

Just a heads up, you’ll have to assign color values to your data tiles when they’re spawned or they’ll appear white when the map scrolls. Easiest way to do this is probably to use a property listener and give each white tile a “data” property or something like that as a trigger.

Hey Dyson - apologies for hassling again.

Just a little confused by your last comment regarding the property listener. Am I right in thinking I give the white tile a “data” property in Tiled, and then during my loadMap() method I need to detect this and change each tile colour accordingly?

I guess I need to look into addPropertyListener() - but I’m a little clueless on that method at the moment. Do you know if any of the MTE examples showcase the use of addPropertyListener()?

Scrub that - found an example in the Iso demo…

However I do have one last question (i hope)…

I have successfully converted over to a tile layer for the heatmap and change the colour upon spawning based on the value.

However when I press a button to toggle the heatmap on or off, I need to run through the tiles and update their colour value based on the waterLevel property - which are stored in an external 2D data array (tileProperties[x][y]) containing all the data for the tiles.

Currently I’m just running through a nested for loop, iterating through this structure, getting the associated tile using getTileObj and changing its colour with the updated value.

Do you think this is the best setup?

I would retrieve the group object for the heatMap layer and iterate through its children with a for-loop. For example, assuming the heatMap was on layer 10 of the map:

local heatMap = mte.getLayerObj(10) for i = 1, heatMap.numChildren, 1 do local locX = heatMap[i].locX local locY = heatMap[i].locY local waterLevel = tileProperties[locX][locY].waterLevel --assign color values --... end

This would be faster than looping through the tileProperties array and calling getTileObj multiple times.

I use groups with no problem, but I didn’t try to put the mte map in a group.

I create my groups after the command mte.loadMap(). 

mte.loadMap("level01.json") local grpHud = display.newGroup()  

If I understand you correctly, you’re creating colored rectangles and adding them to an MTE map layer using addSprite(), and then you are adding them to a custom display group you’ve created for organizational purposes. Adding them to your custom group removes them from MTE’s map layer group. I think the underlying cause here is that Corona SDK will not allow a display object to be a child of two display groups simultaneously. If you add a child of one group to another group, the child will be removed from the first group.

My recommendation is to create a sprite layer(s) on the map above all the other map layers and use this layer group for your heat map display. Being a map layer, it will move and respond to camera control as the others do. You can retrieve the layer’s group object with mte.getLayerObj(), or you can retrieve the map object with “local myMapObj = met.getMapObj()” and reference the desired group by index (myMapObj[1] is the first layer group in the map, myMapObj[#myMapObj] is the last). You can then loop through the group’s children as you like. You can also simply set the group object’s alpha to show or hide it.

Taking this even further, it would be better if the heatMap were a tile layer and the rectangles tiles, because these tiles would then be spawned and culled as you moved the camera. Without this culling (depending on the size of your map) you could end up with an excessively large number of display objects as the player moved the camera around.

Dyson - as always, thanks for your input. That’s exactly the problem and one that I was aware of (Corona moving display objects when changing groups), but unsure as to the best way to overcome this obstacle.

Your suggestion sounds perfect; can I just ask a followup:

You mention it would be preferable to have these as tiles due to culling, which I understand - however I run the following calculation to work out the colour that the tile in the heatmap should be:

[lua]

local waterValue = (self.m_GridArray.tileProperties[child.tileX][child.tileY].waterLevel * 2.55) / 255

print("Child TileX: "…child.tileX)

print("Child TileY: "…child.tileY)

print("Water Value: "…waterValue)

child:setFillColor(0, 0, waterValue, 1)

[/lua]

This allows me to adjust the colour based on a watervalue of 0-100 (and using G2.0 's 0:1 range).

Presumably I could just use a whole bunch of white tiles in a tile layer and adjust the colour accordingly???

Yes, using white tiles and adjusting their color would be best I think. You could also then use the same tiles to display different data and even combine different data sets together for each tile, like displaying an overall growth suitability factor or something of the like. Tile display objects store their associated map location in .locX and .locY, as well as other useful information.

Just a heads up, you’ll have to assign color values to your data tiles when they’re spawned or they’ll appear white when the map scrolls. Easiest way to do this is probably to use a property listener and give each white tile a “data” property or something like that as a trigger.

Hey Dyson - apologies for hassling again.

Just a little confused by your last comment regarding the property listener. Am I right in thinking I give the white tile a “data” property in Tiled, and then during my loadMap() method I need to detect this and change each tile colour accordingly?

I guess I need to look into addPropertyListener() - but I’m a little clueless on that method at the moment. Do you know if any of the MTE examples showcase the use of addPropertyListener()?

Scrub that - found an example in the Iso demo…

However I do have one last question (i hope)…

I have successfully converted over to a tile layer for the heatmap and change the colour upon spawning based on the value.

However when I press a button to toggle the heatmap on or off, I need to run through the tiles and update their colour value based on the waterLevel property - which are stored in an external 2D data array (tileProperties[x][y]) containing all the data for the tiles.

Currently I’m just running through a nested for loop, iterating through this structure, getting the associated tile using getTileObj and changing its colour with the updated value.

Do you think this is the best setup?

I would retrieve the group object for the heatMap layer and iterate through its children with a for-loop. For example, assuming the heatMap was on layer 10 of the map:

local heatMap = mte.getLayerObj(10) for i = 1, heatMap.numChildren, 1 do local locX = heatMap[i].locX local locY = heatMap[i].locY local waterLevel = tileProperties[locX][locY].waterLevel --assign color values --... end

This would be faster than looping through the tileProperties array and calling getTileObj multiple times.