Tile Engine Concerns

Greetings!

My next project will need some form of tile engine and my understanding is that, due to current limitations of Corona, you pretty much can’t create a per-formant engine at this time.

One among many examples would be that creating a simple 100x100x3 map with 32x32 tiles would create 30k display objects (about 8m of ram in my tests) that you would need to shove into a display group. As there is no real ‘camera’ in order to handle scrolling of the map you actually must move the display group containing all of those images.

Even if we get beyond the realities of what 30k tiles does to the render loop by conditionally setting tiles to visible/invisible as the map moves we’re still left with the fact that even my Core i7 drops to 20fps when dragging that group containing 30k tiles.

So, my question is, how do we get around that?

Would a valid solution be to paint 2 or 3 1024x1024 tilemaps in Tiled then save the maps as an image which are then stitched together on the screen and moved around? I would assume that the performance would be much better in that case. Unfortunately I haven’t had time to test my theory as of yet.

At that point we would first need to map x,y coordinates to a ‘cell’ or ‘tile’ in the map. Then, uing that ‘map space’ coordinate, index into a 100x100 table. Each cell of that table would contain a reference to a TileData object that stores whether or not cell is passable, etc, etc.

Does the above sound workable? Can anyone think of other viable solutions to the problem other than ‘wait for corona support for tilemaps to improve so that Lime will eventually work as advertised’ ? [import]uid: 50570 topic_id: 9389 reply_id: 309389[/import]

OK what you want (100 x 100 area using 32 pixel tiles*) is possible at 30 fps, but even at its most optimised (which is roughly where I am now) won’t leave you a great deal of CPU time for other things.

Anyway, here’s how I solved the problem.

First off, rethink how many tiles you need.
The number of visible tiles onscreen at once:
16 x 11. This is the 15 x 10 you’d expect, plus an additional row and column for when the tiles are offset from the top left of the screen.
So this, 16 x 11, is how many active tiles you need.

Second, stop thinking about standard display objects. They are hideously slow.
You need to use sprite sheets instead. These allow you to swap images on a given sprite easily.
What you do is dump all your tiles into the same image, and set it up using the sprite sheet commands.

Next create your grid of tiles, using sprites set to the sprite sheet. Position them correctly and dump them all into a display group (so you can move the display group around instead of individual sprites).

With the sprites, you now have the ability to change individual tiles to whichever graphic you want, by setting it to the relevant frame. Hopefully you can see where this is going :slight_smile:

Final stage is you need a means of converting a given map coordinate into 2 things:

  1. Offset into your map structure
  2. Actual pixel offset (for positioning the display group).

Essentially, if your map data is a nested table structure (so map[x][y] gets you the xth and yth tile), and each tile is 32 pixels wide, then you’d do something akin to the following (psuedo code):

Assumes xPos and yPos is the position in pixels of the top left of the map area you wish to show
Also assumes the screen is 480 x 320 and that the sprites are stored in nested tables :slight_smile:

[code]xTile = math.floor(xPos / 32)
yTile = math.floor(yPos / 32)
xOffset = xPos % 32
yOffset = yPos % 32

for x = 1, 16 do
for y = 1, 11 do
sprite = sprites[x][y]
sprite.currentFrame = map[xTile + x][yTile + y]
end
end

displayGroup.x = -xOffset
displayGroup.y = -yOffset[/code]This is obviously not optimised at all, and omits the setting up of the sprite sheets etc, but hopefully it should give you the idea of how it works

* You said 100 x 100 x 3 - does the x 3 mean you are hoping for 3 layers of parallax while you do this? If so, no it ain’t possible, my comments relate only to a single layer at a time [import]uid: 46639 topic_id: 9389 reply_id: 34331[/import]

I should point out that as a data structure, you’d find it far more efficient to have the map table contain a single number in each cell that is a look up value into a table that just contains tile data.
Actually I could be wrong on that, since I’m not entirely sure on how Lua deals with table references, but in that case you need to make sure that each cell uses the exact same table as every other cell showing the same graphic, as opposed to identical copies.

EG this is bad:

map = { {tile = 1}, {tile = 1}, {tile = 1}}

this is better:

tile1 = {tile = 1}
map = { tile1, tile1, tile1 }

But I’m using something akin to this:

map = { 1, 1, 1 }
tiles = { 1 = {tile = 1} }

so you’d get the tile data by:

tileData = tiles[map[x]]

Actually now I think about it, I might even swap my current method from this last one to the ‘this is better’ above, since it takes out an additional table look-up. I guess the trade off is whether the speed gains while playing are sufficient to make up for the data replacement I’d need to do when initialising the map (my current test map is 160x128, but I’ve got some up to 256x256 tiles). Time to test… :slight_smile: [import]uid: 46639 topic_id: 9389 reply_id: 34333[/import]