Million-Tile Engine; any interest? Feature requests?

Skydrive seems to work. Just really slow. Probably will want to use .txt instead of .rtf (or maybe .html, given you have some images) but regardless, it’s great. You clearly put some thought into the documentation.

Now, I’m also pragmatic enough to say (a) I’ll probably still find bugs and (b) will still be confused by some part of the docs, but it’s still a huge step above most other options.

I just can’t wait to start building and testing it out! [import]uid: 41884 topic_id: 32457 reply_id: 142058[/import]

Would you be interested in beta testing it for me? I’d rather have a second perspective and second eye on it before I start taking people’s money, lest the product be defective in some unforeseen manner.

I used .rtf because some of the files have hyperlinks to document headings for convenience, if opened in an appropriate editor like Word or TextEdit. [import]uid: 99903 topic_id: 32457 reply_id: 142095[/import]

Yeah sure, I was really hoping to go back and rework my RPG engine anyway, would be great to get it running with a solid tile engine.

richard -AT- moogle -DOT- net [import]uid: 41884 topic_id: 32457 reply_id: 142099[/import]

I’ll get it to you ASAP. I’m just trying to track down a little stutter I think is related to timers. Anyway, this is the first map in a three-map demo it’ll come with showing off the basic functionality.

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

It’s a standard retro RPG style control scheme in which the player sprite moves by exactly one block when a direction is pressed.

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

local DpadBack = display.newImageRect(“Dpad.png”, 200, 200)
DpadBack.x = 120
DpadBack.y = display.viewableContentHeight - 120
local DpadUp = display.newRect(DpadBack.x - 37, DpadBack.y - 100, 75, 75)
local DpadDown = display.newRect(DpadBack.x - 37, DpadBack.y + 25, 75, 75)
local DpadLeft = display.newRect(DpadBack.x - 100, DpadBack.y - 37, 75, 75)
local DpadRight = display.newRect(DpadBack.x + 25, DpadBack.y - 37, 75, 75)

mte.loadMap(“map/Demo.json”, “Resource”)

mte.goto({ locX = 30, locY = 106, blockScale = 64 })

local spriteSheet = graphics.newImageSheet(“spriteSheet.png”, {width = 32, height = 32, numFrames = 96})

local layer = mte.getSpriteLayer(1)
print(layer)
local setup = {kind = “sprite”, layer = mte.getSpriteLayer(mte.getVisibleLevel(30, 106)), locX = 30, locY = 106, sourceWidth = 32, sourceHeight = 32}
local options = {
imageSheet = spriteSheet,
sequenceData =
{
{name = “walkUp”, sheet = spriteSheet, frames = {85, 86}, time = 450, loopCount = 0},
{name = “walkDown”, sheet = spriteSheet, frames = {49, 50}, time = 450, loopCount = 0},
{name = “walkLeft”, sheet = spriteSheet, frames = {61, 62}, time = 450, loopCount = 0},
{name = “walkRight”, sheet = spriteSheet, frames = {73, 74}, time = 450, loopCount = 0}
},
xScale = mte.findScale(32, layer) * 1.0,
yScale = mte.findScale(32, layer) * 1.0
}
local player = mte.addSprite(setup, options)

mte.setCameraFocus(player)
local movement = nil

local move = function(event)
if event.target == DpadUp then
if event.phase == “began” or event.phase == “moved” then
movement = “up”
player:setSequence(“walkUp”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadDown then
if event.phase == “began” or event.phase == “moved” then
movement = “down”
player:setSequence(“walkDown”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadLeft then
if event.phase == “began” or event.phase == “moved” then
movement = “left”
player:setSequence(“walkLeft”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadRight then
if event.phase == “began” or event.phase == “moved” then
movement = “right”
player:setSequence(“walkRight”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
end
end

local gameLoop = function(event)
mte.updateCamera(0, 0)
mte.debug()

local objects = mte.getObjectProperties({locX = player.locX, locY = player.locY})
if objects ~= nil then
print(objects[1].name)
for i = 1, #objects, 1 do
if objects[i].type == “changeLevel” then
mte.changeSpriteLayer(player, mte.getSpriteLayer(tonumber(objects[i].properties.level)))
elseif objects[i].type == “hideLevels” then
local layerObjects = mte.getLayerObj()
local layers = mte.getLayers()
if objects[i].properties.levels == “above” then
for i = 1, #layers, 1 do
if layers[i].properties.Level > player.level then
layerObjects[i].isVisible = false
end
end
elseif objects[i].properties.levels == “below” then
for i = 1, # layers, 1 do
if layers[i].properties.Level < player.level then
layerObjects[i].isVisible = false
end
end
end
elseif objects[i].type == “showLevels” then
local layerObjects = mte.getLayerObj()
local layers = mte.getLayers()
if objects[i].properties.levels == “above” then
for i = 1, # layers, 1 do
if layers[i].properties.Level > player.level then
layerObjects[i].isVisible = true
end
end
elseif objects[i].properties.levels == “below” then
for i = 1, # layers, 1 do
if layers[i].properties.Level < player.level then
layerObjects[i].isVisible = true
end
end
end
elseif objects[i].type == “gotoMap” then
end
end
end

if player.timer == nil then
if movement == “up” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX, locY = player.locY - 1})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 0, -10)
mte.moveSpriteTo({sprite = player, locX = player.locX, locY = player.locY - 1, time = 6, easing = “linear”})
end
elseif movement == “down” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX, locY = player.locY + 1})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 0, 10)
mte.moveSpriteTo({sprite = player, locX = player.locX, locY = player.locY + 1, time = 6, easing = “linear”})
end
elseif movement == “left” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX - 1, locY = player.locY})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, -10, 0)
mte.moveSpriteTo({sprite = player, locX = player.locX - 1, locY = player.locY, time = 6, easing = “linear”})
end
elseif movement == “right” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX + 1, locY = player.locY})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 10, 0)
mte.moveSpriteTo({sprite = player, locX = player.locX + 1, locY = player.locY, time = 6, easing = “linear”})
end
else
player:pause()
end
end

DpadUp:toFront()
DpadDown:toFront()
DpadLeft:toFront()
DpadRight:toFront()
DpadBack:toFront()

end

DpadUp:addEventListener(“touch”, move)
DpadDown:addEventListener(“touch”, move)
DpadLeft:addEventListener(“touch”, move)
DpadRight:addEventListener(“touch”, move)

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

I’d be interested in beta testing, in fact would be happy to pay up front to get early access.

Will I be able to create maps dynamically rather than through Tiled? I guess I could create a grass background in tiled, import all the other tiles I need in the game and then manually update the map as required within the code? [import]uid: 93133 topic_id: 32457 reply_id: 142178[/import]

With some minor finagling, sure, easily. The thing is, exported tile maps only contain the properties of the tilesets used to add tiles to the map- adding new tilesets without actually using some of their tiles does not add them to the export. So, what you would do is put one tile from each set you need in the corner or in a lower level, or anywhere out of the way. Or you could just go in to the json file and add them yourself. When MTE runs it will load those tilesets, and you can use mte.updateTile to build your map, or allow users to alter the map sandbox style, or whatever. When they’re done you would use mte.getMap, encode that array with json, and save it in the DocumentsDirectory to be loaded again later.

Just keep in mind that the map arrays in the engine do not conform exactly to the standard output of Tiled. This was a performance compromise. Navigating a 2D array of tiles is faster than converting coordinates to Tiled’s 1D arrays on every tile manipulation. MTE will load MTE-modified maps just fine, but other tools won’t. I guess I could add a toggle to keep the original Tiled data intact at the expensive of higher memory usage…

The stutter I mentioned was indeed caused by timer.performWithDelay, so now the engine uses it’s own internal counters updating in enterFrame with mte.updateSprites. [import]uid: 99903 topic_id: 32457 reply_id: 142197[/import]

As for earlier paid beta access, I’d open that up if sellbox had a built-in system for dispensing updates to previous buyers. They say one is in the works for this month. I guess the price will be… I don’t know. Less than 20 dollars, I’m thinking.

I may also put the original, horrendously convoluted, extraordinarily optimized, ginormous Corona SDK Engine seen in the videos in the OP up for something like 80 bucks for anyone with the courage and fortitude to try to tackle it.

That’ll be something for another day, though. Immediately in the future are more improvements and fixes for MTE, and then another unrelated engine project afterwards, continuing the mission of making Corona do what it can’t. [import]uid: 99903 topic_id: 32457 reply_id: 142205[/import]

Thanks, sounds like I’ll be able to do what I want which is the sandbox scenario. Yeah, I’m waiting for Sellbox to add that feature too - however you do get the e-mail address of every customer so you could distribute updates that way. [import]uid: 93133 topic_id: 32457 reply_id: 142232[/import]

If it’s of any use, we use Sellfy to sell our GG libs and it allows us to send out emails/updates/newsletters to all customers etc. There’s also Gumroad and Merchee however I haven’t tried those yet. [import]uid: 119420 topic_id: 32457 reply_id: 142241[/import]

Thanks for the tip. I’ll look into those as well. [import]uid: 99903 topic_id: 32457 reply_id: 142254[/import]

Hi Dyson,

I am also interested in your work. I’m in a very early state of develoing a 2D puzzle game with maps which can be created via Tiled or (alter hopefully) with an ingame editor.

I hope to see your work soo puchasable.

Imho, I think $10 is to cheap, because I also expect to have a little support on code questions when puchasing an product. No idea how much support I can get for $10? [import]uid: 200446 topic_id: 32457 reply_id: 142282[/import]

Looks cool!

C [import]uid: 147322 topic_id: 32457 reply_id: 142260[/import]

Thanks for the shout-out Danny. I enjoy working within limits, because I enjoy having limits to break. I’ve seen it said many times that Corona is not a good tool for creating games using large tilemaps, and I knew immediately that something could be done about that.

Anyway, I was a little optimistic about the timeline I mentioned earlier. As usual, a few little things came up that needed my attention. The most significant change is that MTE now detects Object Layers created in Tiled and allows users to access and modify those objects. What I have been calling Objects up till now are now called Sprites to differentiate the two.

I’m working on a few example maps now. In the meantime, here are some of the reference files to look at:

API:
https://skydrive.live.com/redir?resid=73D2274FE560C959!346&authkey=!ANMCiIgC_W43Dbs

Reserved Properties:
https://skydrive.live.com/redir?resid=73D2274FE560C959!347&authkey=!AEI5sLQzVj6WzPw

Map Structure:
https://skydrive.live.com/redir?resid=73D2274FE560C959!349&authkey=!AD-sAE1HwfBwXwE

Creating Tilesets HOWTO:
https://skydrive.live.com/redir?resid=73D2274FE560C959!348&authkey=!ANTcTtww0HBCW7g

Let me know if something’s wrong with the files; I don’t use skydrive very often. [import]uid: 99903 topic_id: 32457 reply_id: 141993[/import]

Hi, Dyson.

I’ll echo the other interested parties on testing, though I don’t know if I’d get around to doing anything useful.

Out of curiosity, does the editor dispatch any events when you paint / erase / etc. a tile? I can elaborate a little on where this question is coming from (heading out the door…), though the gist is “how would I migrate my workflow over from using my own (lame) editor?” [import]uid: 27791 topic_id: 32457 reply_id: 142818[/import]

Skydrive seems to work. Just really slow. Probably will want to use .txt instead of .rtf (or maybe .html, given you have some images) but regardless, it’s great. You clearly put some thought into the documentation.

Now, I’m also pragmatic enough to say (a) I’ll probably still find bugs and (b) will still be confused by some part of the docs, but it’s still a huge step above most other options.

I just can’t wait to start building and testing it out! [import]uid: 41884 topic_id: 32457 reply_id: 142058[/import]

Would you be interested in beta testing it for me? I’d rather have a second perspective and second eye on it before I start taking people’s money, lest the product be defective in some unforeseen manner.

I used .rtf because some of the files have hyperlinks to document headings for convenience, if opened in an appropriate editor like Word or TextEdit. [import]uid: 99903 topic_id: 32457 reply_id: 142095[/import]

Yeah sure, I was really hoping to go back and rework my RPG engine anyway, would be great to get it running with a solid tile engine.

richard -AT- moogle -DOT- net [import]uid: 41884 topic_id: 32457 reply_id: 142099[/import]

I’ll get it to you ASAP. I’m just trying to track down a little stutter I think is related to timers. Anyway, this is the first map in a three-map demo it’ll come with showing off the basic functionality.

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

It’s a standard retro RPG style control scheme in which the player sprite moves by exactly one block when a direction is pressed.

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

local DpadBack = display.newImageRect(“Dpad.png”, 200, 200)
DpadBack.x = 120
DpadBack.y = display.viewableContentHeight - 120
local DpadUp = display.newRect(DpadBack.x - 37, DpadBack.y - 100, 75, 75)
local DpadDown = display.newRect(DpadBack.x - 37, DpadBack.y + 25, 75, 75)
local DpadLeft = display.newRect(DpadBack.x - 100, DpadBack.y - 37, 75, 75)
local DpadRight = display.newRect(DpadBack.x + 25, DpadBack.y - 37, 75, 75)

mte.loadMap(“map/Demo.json”, “Resource”)

mte.goto({ locX = 30, locY = 106, blockScale = 64 })

local spriteSheet = graphics.newImageSheet(“spriteSheet.png”, {width = 32, height = 32, numFrames = 96})

local layer = mte.getSpriteLayer(1)
print(layer)
local setup = {kind = “sprite”, layer = mte.getSpriteLayer(mte.getVisibleLevel(30, 106)), locX = 30, locY = 106, sourceWidth = 32, sourceHeight = 32}
local options = {
imageSheet = spriteSheet,
sequenceData =
{
{name = “walkUp”, sheet = spriteSheet, frames = {85, 86}, time = 450, loopCount = 0},
{name = “walkDown”, sheet = spriteSheet, frames = {49, 50}, time = 450, loopCount = 0},
{name = “walkLeft”, sheet = spriteSheet, frames = {61, 62}, time = 450, loopCount = 0},
{name = “walkRight”, sheet = spriteSheet, frames = {73, 74}, time = 450, loopCount = 0}
},
xScale = mte.findScale(32, layer) * 1.0,
yScale = mte.findScale(32, layer) * 1.0
}
local player = mte.addSprite(setup, options)

mte.setCameraFocus(player)
local movement = nil

local move = function(event)
if event.target == DpadUp then
if event.phase == “began” or event.phase == “moved” then
movement = “up”
player:setSequence(“walkUp”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadDown then
if event.phase == “began” or event.phase == “moved” then
movement = “down”
player:setSequence(“walkDown”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadLeft then
if event.phase == “began” or event.phase == “moved” then
movement = “left”
player:setSequence(“walkLeft”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
elseif event.target == DpadRight then
if event.phase == “began” or event.phase == “moved” then
movement = “right”
player:setSequence(“walkRight”)
elseif event.phase == “ended” or event.phase == “cancelled” then
movement = nil
end
end
end

local gameLoop = function(event)
mte.updateCamera(0, 0)
mte.debug()

local objects = mte.getObjectProperties({locX = player.locX, locY = player.locY})
if objects ~= nil then
print(objects[1].name)
for i = 1, #objects, 1 do
if objects[i].type == “changeLevel” then
mte.changeSpriteLayer(player, mte.getSpriteLayer(tonumber(objects[i].properties.level)))
elseif objects[i].type == “hideLevels” then
local layerObjects = mte.getLayerObj()
local layers = mte.getLayers()
if objects[i].properties.levels == “above” then
for i = 1, #layers, 1 do
if layers[i].properties.Level > player.level then
layerObjects[i].isVisible = false
end
end
elseif objects[i].properties.levels == “below” then
for i = 1, # layers, 1 do
if layers[i].properties.Level < player.level then
layerObjects[i].isVisible = false
end
end
end
elseif objects[i].type == “showLevels” then
local layerObjects = mte.getLayerObj()
local layers = mte.getLayers()
if objects[i].properties.levels == “above” then
for i = 1, # layers, 1 do
if layers[i].properties.Level > player.level then
layerObjects[i].isVisible = true
end
end
elseif objects[i].properties.levels == “below” then
for i = 1, # layers, 1 do
if layers[i].properties.Level < player.level then
layerObjects[i].isVisible = true
end
end
end
elseif objects[i].type == “gotoMap” then
end
end
end

if player.timer == nil then
if movement == “up” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX, locY = player.locY - 1})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 0, -10)
mte.moveSpriteTo({sprite = player, locX = player.locX, locY = player.locY - 1, time = 6, easing = “linear”})
end
elseif movement == “down” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX, locY = player.locY + 1})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 0, 10)
mte.moveSpriteTo({sprite = player, locX = player.locX, locY = player.locY + 1, time = 6, easing = “linear”})
end
elseif movement == “left” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX - 1, locY = player.locY})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, -10, 0)
mte.moveSpriteTo({sprite = player, locX = player.locX - 1, locY = player.locY, time = 6, easing = “linear”})
end
elseif movement == “right” then
local detect = mte.getTileProperties({level = player.level, locX = player.locX + 1, locY = player.locY})
local tile = 0
for i = 1, #detect, 1 do
if detect[i].tile ~= 0 then --check for empty space/void. In other words, don’t walk off cliffs.
tile = detect[i].tile
end
if detect[i].properties ~= nil then
if detect[i].properties.solid ~= nil then
detect = “stop”
player:pause()
break
end
end
end
if detect ~= “stop” and tile ~= 0 then
if player.isPlaying == false then
player:play()
end
–mte.moveSprite(player, 10, 0)
mte.moveSpriteTo({sprite = player, locX = player.locX + 1, locY = player.locY, time = 6, easing = “linear”})
end
else
player:pause()
end
end

DpadUp:toFront()
DpadDown:toFront()
DpadLeft:toFront()
DpadRight:toFront()
DpadBack:toFront()

end

DpadUp:addEventListener(“touch”, move)
DpadDown:addEventListener(“touch”, move)
DpadLeft:addEventListener(“touch”, move)
DpadRight:addEventListener(“touch”, move)

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

I’d be interested in beta testing, in fact would be happy to pay up front to get early access.

Will I be able to create maps dynamically rather than through Tiled? I guess I could create a grass background in tiled, import all the other tiles I need in the game and then manually update the map as required within the code? [import]uid: 93133 topic_id: 32457 reply_id: 142178[/import]

With some minor finagling, sure, easily. The thing is, exported tile maps only contain the properties of the tilesets used to add tiles to the map- adding new tilesets without actually using some of their tiles does not add them to the export. So, what you would do is put one tile from each set you need in the corner or in a lower level, or anywhere out of the way. Or you could just go in to the json file and add them yourself. When MTE runs it will load those tilesets, and you can use mte.updateTile to build your map, or allow users to alter the map sandbox style, or whatever. When they’re done you would use mte.getMap, encode that array with json, and save it in the DocumentsDirectory to be loaded again later.

Just keep in mind that the map arrays in the engine do not conform exactly to the standard output of Tiled. This was a performance compromise. Navigating a 2D array of tiles is faster than converting coordinates to Tiled’s 1D arrays on every tile manipulation. MTE will load MTE-modified maps just fine, but other tools won’t. I guess I could add a toggle to keep the original Tiled data intact at the expensive of higher memory usage…

The stutter I mentioned was indeed caused by timer.performWithDelay, so now the engine uses it’s own internal counters updating in enterFrame with mte.updateSprites. [import]uid: 99903 topic_id: 32457 reply_id: 142197[/import]