Million-Tile Engine; any interest? Feature requests?

I’ve spent the last seven months or so working on the engine for a game similar to Terraria and Junk Jack. Making such a thing work required finding a way to 1) handle very large tile maps 2) dynamically generate terrain with perlin noise and 3) save player modification to enormous tile maps on the fly. It occurs to me now that at least some of these things would be useful to other developers, particularly people working on RPG’s with large overworlds.

“Million-Tile Engine” is my extremely creative and original name for the engine. The main limiting factors are device memory and the number of simultaneous onscreen tiles. The engine couldn’t care less whether the tile map is 40 x 40 or 1500 x 800 tiles, so long as it has the memory. Both will render smoothly. 1100 x 800 and 1500 x 800 are the sizes I’ve been working with on the iPad 2 up till now. Everything is written in Lua.

Running in the simulator:

http://www.youtube.com/watch?v=mNMxUarjTGk

http://www.youtube.com/watch?v=7BUBZLHOF1Y

http://www.youtube.com/watch?v=DJsHMH2eJyE

Running on an iPad 2:

http://www.youtube.com/watch?v=-oEPuqDZWWE

I’m hoping to sell this for $30-$50, something in that range.

The engine isn’t ready for sale yet. I’m working to make it more user friendly and adding support for maps made in Tiled. Unfortunately I have not made extensive use of Tiled up till now, so I’m not sure what kind of functionality people are looking for. Any suggestions would be appreciated. If people have Tiled maps they can send me to test with, that would be very helpful.

What other features would you be interested in? [import]uid: 99903 topic_id: 32457 reply_id: 332457[/import]

This is the code for the second simulator video of the simple scrolling map. Changing the display grid scale would be useful for cinematic effects in RPGs, I think, like constraining the view during important personal conversations or moving far out for grandiose scenes. That is the main functionality on display here.

A lot is going on under the hood. mte.setupDisplay(72) flushes the onscreen display grid, calculates the dimensions of the display grid needed to cover the screen with tiles scaled to 72x72 pixels, and creates all the display objects for the display grid. This function can be called at any time without disrupting the data stored in the tile map itself.

mte.goto(20, 10) is pretty self explanatory. It is reloading the grid so that the camera position is at location 20, 10 on the tile map, and reloading in the tile graphics.

mte.moveCamera is where a lot of the magic happens. It handles the functions responsible for the custom culling solution that makes this all possible to begin with.

mte.debug simply creates the red debug text if it doesn’t already exist and fills it with debug information about where the camera is and what it is doing.

Maps automatically loop in every direction, which is why some paths just end. I’ve also created new layers using tiles without transparent backgrounds, which is why paths rather sloppily overlap other areas. This map did not have to look pretty, I just needed something for preliminary testing. Now that basic Tiled functionality is in place I’d like to get my hands on larger, prettier maps for testing purposes if anyone would like to volunteer one of theirs.

Preferably the tilesets would not have any borders or margins. For some reason Corona’s imagesheet option for borders isn’t working on my end.

[code]
display.setStatusBar( display.HiddenStatusBar )
local mte = require “mte” --Load the Million-Tile Engine

mte.loadMap(“jsonMap3.json”, “json”)

mte.setupDisplay(72)

mte.goto(20, 10)

local velX = -1
local velY = 1
local timer = 0
local gameLoop = function(event)

mte.moveCamera(velX, velY)
mte.debug() --Displays red on-screen debug values

timer = timer + 1
if timer > 100 then
velX = math.random(-4, 4)
velY = math.random(-4, 4)
local size = 8 * math.random(4, 12)
print("Size: "…size)
mte.setupDisplay(size)
mte.goto(math.random(1, 40), math.random(1, 40))
timer = 0
end
end

Runtime:addEventListener(“enterFrame”, gameLoop)
[/code] [import]uid: 99903 topic_id: 32457 reply_id: 129088[/import]

Hey dyson,

There is an old thread here where someone suggested a way to create a tile engine by never actually moving/removing tiles and instead just changing the image on them. I built my own version and it works spectacularly (basically no performance issues on iPhone4) and without any of the downsides of Lime…

…except that just building all of the functions to work with it would be a nightmare. If there’s one thing Lime does fairly well, it’s that it has a large number of core functions to do the basics and pull from Tiled as needed.

  1. Yes, I would definitely be interested. I can tell you from spending a month on my own solution that while I enjoy coding, I just can’t afford to blow 3 months figuring out encoder/decoders and every little function needed to get my game running. (That’s why I originally bought Lime in the first place!) Pretty much had to set my work aside so if someone else has figured it out that would be awesome.

  2. Off the top of my head the top priority features would be:

  • Performance, though this goes without saying. I need something that can run 256x256 tile grids.
  • Must run as an external module (no .seeall; this should be fairly trivial, but if you’re going to sell it as a package it should be able to run properly isolated and support being run out of a folder)
  • All converter functions (ie: getTileAt, getWorldPos, getScreenPos, all that stuff)
  • Tile lookup functions (this is important for Tiled; how do I look up the properties for either a tile from the tileset or a tile on-screen?)
  • A camera scroller locked to a sprite of choice (here’s your RPG guy walking around, lock the camera to him)
  • Sandwich support (I’d be happy even with a basic two-layer sandwich, but generally with Tiled you get to use multiple layers, and for basic implementations this means a ground layer below and a sky layer above, with your sprites sandwiched in the middle.)
  • You’ve mentioned Looping (awesome!) but definitely needs on/off support there.

I’m not so interested in spawning sprites via Tiled though I guess it could be interesting if it worked. The implementation in Lime was problematic and Tiled is not exactly super with sprite support so it’s of lower priority to me. On-the-fly tile grid saving as you suggest is interesting though!

  1. Difficult to tell from your code but the only thing I’d warn in general is to try and follow Corona’s ideas on function simplicity; namely don’t bog down a function with too many vars when you could use a table instead, and try to build function names that make sense to the average user. Documentation is always hurting for new products like this off the bat so it helps if it’s intuitive for new users to figure out how to get it going. :slight_smile:

  2. border should work, though I know we noticed a problem in the Lime thread about how the Windows SDK compiler wasn’t using it while the OSX SDK compiler was. [import]uid: 41884 topic_id: 32457 reply_id: 129098[/import]

I don’t know of any way to change the image in a display object without removing the object and creating a new one. I’d be interested in learning what you came up with the thread you based it on. Doing a search of these forums returns such useful results as “Recent Posts” pages, over and over.

EDIT: I think I may have found the thread you were talking about. Apparently people are using sprites as tiles and loading the different tile graphics as animation frames. I’d never thought of that. I imagine creating sprites has a larger performance impact than newImageRect(), which is relatively quick, but merely changing an animation frame must be faster still…

Definitely gives me something to think about, that and your other suggestions.

[import]uid: 99903 topic_id: 32457 reply_id: 129106[/import]

Well if you have a solution that works, on iPhone4, without framerate stutter then that’s fine.

Yeah, you’ve got the right thread. All of the tiles are created at the start and then setFrame() is used to simply change the image on it. Ridiculously fast even though it basically uses a Runtime listener to update the tiles.

I can tell you from personal experience setting Frames is orders of magnitude faster than moving or creating the tiles themselves; I spent a month building a tile engine where all that happens is I move and update the tiles (so if you move left, I move the leftmost tiles to the right and change their images), but even updating one row of tiles turned out to be so bad for performance I had to give that up. Even filed a bug about it - it seems that if you sweep your finger a lot it’s possible to just kill your framerate in some cases.

Actually, that’s the other tip I would give you: Don’t just test on iPad. Generally with the experimental tile engine work I was doing, iPad 1 and 2 would have little to no problems whereas iPhone4 would start heavily dropping frames in some circumstances. If you use iPad2 as a target then you would need to expect 4S+ to get similar phone performance.

Profiler is a great way to check overall CPU usage but I highly recommend the iPhone4 as your target platform at this point in time. [import]uid: 41884 topic_id: 32457 reply_id: 129108[/import]

This is the code for the second simulator video of the simple scrolling map. Changing the display grid scale would be useful for cinematic effects in RPGs, I think, like constraining the view during important personal conversations or moving far out for grandiose scenes. That is the main functionality on display here.

A lot is going on under the hood. mte.setupDisplay(72) flushes the onscreen display grid, calculates the dimensions of the display grid needed to cover the screen with tiles scaled to 72x72 pixels, and creates all the display objects for the display grid. This function can be called at any time without disrupting the data stored in the tile map itself.

mte.goto(20, 10) is pretty self explanatory. It is reloading the grid so that the camera position is at location 20, 10 on the tile map, and reloading in the tile graphics.

mte.moveCamera is where a lot of the magic happens. It handles the functions responsible for the custom culling solution that makes this all possible to begin with.

mte.debug simply creates the red debug text if it doesn’t already exist and fills it with debug information about where the camera is and what it is doing.

Maps automatically loop in every direction, which is why some paths just end. I’ve also created new layers using tiles without transparent backgrounds, which is why paths rather sloppily overlap other areas. This map did not have to look pretty, I just needed something for preliminary testing. Now that basic Tiled functionality is in place I’d like to get my hands on larger, prettier maps for testing purposes if anyone would like to volunteer one of theirs.

Preferably the tilesets would not have any borders or margins. For some reason Corona’s imagesheet option for borders isn’t working on my end.

[code]
display.setStatusBar( display.HiddenStatusBar )
local mte = require “mte” --Load the Million-Tile Engine

mte.loadMap(“jsonMap3.json”, “json”)

mte.setupDisplay(72)

mte.goto(20, 10)

local velX = -1
local velY = 1
local timer = 0
local gameLoop = function(event)

mte.moveCamera(velX, velY)
mte.debug() --Displays red on-screen debug values

timer = timer + 1
if timer > 100 then
velX = math.random(-4, 4)
velY = math.random(-4, 4)
local size = 8 * math.random(4, 12)
print("Size: "…size)
mte.setupDisplay(size)
mte.goto(math.random(1, 40), math.random(1, 40))
timer = 0
end
end

Runtime:addEventListener(“enterFrame”, gameLoop)
[/code] [import]uid: 99903 topic_id: 32457 reply_id: 129088[/import]

Hey dyson,

There is an old thread here where someone suggested a way to create a tile engine by never actually moving/removing tiles and instead just changing the image on them. I built my own version and it works spectacularly (basically no performance issues on iPhone4) and without any of the downsides of Lime…

…except that just building all of the functions to work with it would be a nightmare. If there’s one thing Lime does fairly well, it’s that it has a large number of core functions to do the basics and pull from Tiled as needed.

  1. Yes, I would definitely be interested. I can tell you from spending a month on my own solution that while I enjoy coding, I just can’t afford to blow 3 months figuring out encoder/decoders and every little function needed to get my game running. (That’s why I originally bought Lime in the first place!) Pretty much had to set my work aside so if someone else has figured it out that would be awesome.

  2. Off the top of my head the top priority features would be:

  • Performance, though this goes without saying. I need something that can run 256x256 tile grids.
  • Must run as an external module (no .seeall; this should be fairly trivial, but if you’re going to sell it as a package it should be able to run properly isolated and support being run out of a folder)
  • All converter functions (ie: getTileAt, getWorldPos, getScreenPos, all that stuff)
  • Tile lookup functions (this is important for Tiled; how do I look up the properties for either a tile from the tileset or a tile on-screen?)
  • A camera scroller locked to a sprite of choice (here’s your RPG guy walking around, lock the camera to him)
  • Sandwich support (I’d be happy even with a basic two-layer sandwich, but generally with Tiled you get to use multiple layers, and for basic implementations this means a ground layer below and a sky layer above, with your sprites sandwiched in the middle.)
  • You’ve mentioned Looping (awesome!) but definitely needs on/off support there.

I’m not so interested in spawning sprites via Tiled though I guess it could be interesting if it worked. The implementation in Lime was problematic and Tiled is not exactly super with sprite support so it’s of lower priority to me. On-the-fly tile grid saving as you suggest is interesting though!

  1. Difficult to tell from your code but the only thing I’d warn in general is to try and follow Corona’s ideas on function simplicity; namely don’t bog down a function with too many vars when you could use a table instead, and try to build function names that make sense to the average user. Documentation is always hurting for new products like this off the bat so it helps if it’s intuitive for new users to figure out how to get it going. :slight_smile:

  2. border should work, though I know we noticed a problem in the Lime thread about how the Windows SDK compiler wasn’t using it while the OSX SDK compiler was. [import]uid: 41884 topic_id: 32457 reply_id: 129098[/import]

I don’t know of any way to change the image in a display object without removing the object and creating a new one. I’d be interested in learning what you came up with the thread you based it on. Doing a search of these forums returns such useful results as “Recent Posts” pages, over and over.

EDIT: I think I may have found the thread you were talking about. Apparently people are using sprites as tiles and loading the different tile graphics as animation frames. I’d never thought of that. I imagine creating sprites has a larger performance impact than newImageRect(), which is relatively quick, but merely changing an animation frame must be faster still…

Definitely gives me something to think about, that and your other suggestions.

[import]uid: 99903 topic_id: 32457 reply_id: 129106[/import]

Well if you have a solution that works, on iPhone4, without framerate stutter then that’s fine.

Yeah, you’ve got the right thread. All of the tiles are created at the start and then setFrame() is used to simply change the image on it. Ridiculously fast even though it basically uses a Runtime listener to update the tiles.

I can tell you from personal experience setting Frames is orders of magnitude faster than moving or creating the tiles themselves; I spent a month building a tile engine where all that happens is I move and update the tiles (so if you move left, I move the leftmost tiles to the right and change their images), but even updating one row of tiles turned out to be so bad for performance I had to give that up. Even filed a bug about it - it seems that if you sweep your finger a lot it’s possible to just kill your framerate in some cases.

Actually, that’s the other tip I would give you: Don’t just test on iPad. Generally with the experimental tile engine work I was doing, iPad 1 and 2 would have little to no problems whereas iPhone4 would start heavily dropping frames in some circumstances. If you use iPad2 as a target then you would need to expect 4S+ to get similar phone performance.

Profiler is a great way to check overall CPU usage but I highly recommend the iPhone4 as your target platform at this point in time. [import]uid: 41884 topic_id: 32457 reply_id: 129108[/import]

How do you prefer to designate a layer in Tiled as the one for Sprites? For example, do you set a property for the layer? Or do you program your app to look for keywords in the layer’s title? [import]uid: 99903 topic_id: 32457 reply_id: 129656[/import]

Tiled lets you outright make a type of layer for Objects, so I do that and then set the layer order appropriately. (Haven’t looked into this but since you can’t place tiles on an object layer, I can only assume the XML output recognizes the difference.) [import]uid: 41884 topic_id: 32457 reply_id: 129666[/import]

How do you prefer to designate a layer in Tiled as the one for Sprites? For example, do you set a property for the layer? Or do you program your app to look for keywords in the layer’s title? [import]uid: 99903 topic_id: 32457 reply_id: 129656[/import]

Tiled lets you outright make a type of layer for Objects, so I do that and then set the layer order appropriately. (Haven’t looked into this but since you can’t place tiles on an object layer, I can only assume the XML output recognizes the difference.) [import]uid: 41884 topic_id: 32457 reply_id: 129666[/import]

If you could send one of your .tmx tilemaps and the associated graphics to my user name @hotmail.com, that would be very helpful. A map with a good representation of all the different techniques and properties you employ would be best. Makes more sense then asking you how you would do something in Tiled every time I run into something unfamiliar or hit a task with multiple possible solutions. [import]uid: 99903 topic_id: 32457 reply_id: 129898[/import]

If you could send one of your .tmx tilemaps and the associated graphics to my user name @hotmail.com, that would be very helpful. A map with a good representation of all the different techniques and properties you employ would be best. Makes more sense then asking you how you would do something in Tiled every time I run into something unfamiliar or hit a task with multiple possible solutions. [import]uid: 99903 topic_id: 32457 reply_id: 129898[/import]

MTE: Advanced Perspective and Layer Lighting
http://www.youtube.com/watch?v=ajkAaYqA5r8

The code on the user end stays very simple:

[code]
display.setStatusBar( display.HiddenStatusBar )
local mte = require “MTE.mte”

mte.loadMap(“NewParallax4b.json”, “json”)
mte.goto(28, 10, 56)

local velX = 1
local velY = 2
local gameLoop = function(event)

mte.moveCamera(velX, velY)
mte.debug() --Displays red on-screen debug values

end

Runtime:addEventListener(“enterFrame”, gameLoop)
[/code] [import]uid: 99903 topic_id: 32457 reply_id: 130008[/import]

MTE: Advanced Perspective and Layer Lighting
http://www.youtube.com/watch?v=ajkAaYqA5r8

The code on the user end stays very simple:

[code]
display.setStatusBar( display.HiddenStatusBar )
local mte = require “MTE.mte”

mte.loadMap(“NewParallax4b.json”, “json”)
mte.goto(28, 10, 56)

local velX = 1
local velY = 2
local gameLoop = function(event)

mte.moveCamera(velX, velY)
mte.debug() --Displays red on-screen debug values

end

Runtime:addEventListener(“enterFrame”, gameLoop)
[/code] [import]uid: 99903 topic_id: 32457 reply_id: 130008[/import]

oops, misread. Well send my tmx, it’s not much (really, quite minimal) along with some notes.

The perspective and lighting in that video are wtf awesome. I am excited to use this. [import]uid: 41884 topic_id: 32457 reply_id: 130029[/import]

I think it looks cool :slight_smile:

Larry

www.TinyTapApps.com [import]uid: 11860 topic_id: 32457 reply_id: 130072[/import]

oops, misread. Well send my tmx, it’s not much (really, quite minimal) along with some notes.

The perspective and lighting in that video are wtf awesome. I am excited to use this. [import]uid: 41884 topic_id: 32457 reply_id: 130029[/import]