Ludum Fail :) Loading Tiled maps, am I being daft?

After spending last night working on a map for a Ludum Dare entry, this morning I went to try and load it.

I failed. Miserably.

Since then I have spent 8 hours trying to get EITHER PonyWolfs Tiled loader to work, or Roaming Gamers Tiled loader to work, and I failed at both.

PonyWolfs keeps giving me a failure on lookupGID being nil.

RoamingGamers entry I will confess I couldn’t figure out how to run it. I tried the RGDocs, I tried to pull out the code from validations, but I couldn’t seem to get there.

I then created a brand new map, 20x20 and used 1 tile and 1 layer. (In case it was me). Put the json/lua/tmx/tsx & timesheet image files in the same directory with the same results.

Now, I *am* aware that Tiled is not on version 1.02, but I don’t know if these loaders are working fine with that version. I did try to load/re-save the existing samples and they worked fine.

RGTiled Loader using version .010: Using this…

require "ssk.loadSSK" -- Create Tiled Loader helper object local level = ssk.tiled.new() -- Data file is in folder 'tests/tiled/' level.setLevelsPath( "maps/gstiles" ) -- Load the level file 'dummy.lua' and pass no specific extra settings. level.load( "tilemap" ) level.draw( ) --I didn't get as far as adding the scene group yet

Provides this error.

main.lua:4: attempt to index field ‘tiled’ (a nil value)

For the PonyWolf version I am using the GitHub version and changing these lines…

local mapData = json.decodeFile(system.pathForFile("maps/gstiles/tilemap.json", system.ResourceDirectory)) -- load from json export local map = tiled.new(mapData, "maps/gstiles")

The error returned is…

/com/ponywolf/ponytiled.lua:126: attempt to compare number with nil

/com/ponywolf/ponytiled.lua:126: in function 'gidLookup’

(I am getting ‘object.gid’ loaded around 181)

The primary goal is to just get the map on screen now, I’ve all but abandoned the Ludum Dare attempt, I had figured the map loading would be an hour tops :slight_smile:

At the end of the day, I’m not too bothered as to which loader I use. I do plan on using Tiled’s collision editor so I don’t walk through walls and the rest I’ll worry about later. 

If I get this working, at least I can consider the Corona/Defold Jam instead :slight_smile:

Thanks guys, and if I’m being daft, I apologize - late night Ludum Dare sessions may do that to a person!

:wacko:

I will assist you with the PonyTiled version, as that is the one I am using. @roaminggamer will help you a lot more with his own version (if he sees this post). First off, are you sure you are using the latest version of PonyTiled? I had a problem with this where I could not load in my tile layers and I realized my version was outdated.

Check if the code structure looks like this:

-- Project: PonyTiled a Corona Tiled Map Loader -- -- Loads LUA saved map files from Tiled http://www.mapeditor.org/ local M = {} local physics = require "physics" local FlippedHorizontallyFlag = 0x80000000 local FlippedVerticallyFlag = 0x40000000 local FlippedDiagonallyFlag = 0x20000000 local ClearFlag = 0x1FFFFFFF local function hasbit(x, p) return x % (p + p) \>= p end local function setbit(x, p) return hasbit(x, p) and x or x + p end local function clearbit(x, p) return hasbit(x, p) and x - p or x end local function inherit(image, properties) for k,v in pairs(properties) do image[k] = v end return image end local function centerAnchor(image) if image.contentBounds then local bounds = image.contentBounds local actualCenterX, actualCenterY = (bounds.xMin + bounds.xMax)/2 , (bounds.yMin + bounds.yMax)/2 image.anchorX, image.anchorY = 0.5, 0.5 image.x = actualCenterX image.y = actualCenterY end end local function decodeTiledColor(hex) hex = hex or "#FF888888" hex = hex:gsub("#","") local function hexToFloat(part) return tonumber("0x".. part or "00") / 255 end local a, r, g, b = hexToFloat(hex:sub(1,2)), hexToFloat(hex:sub(3,4)), hexToFloat(hex:sub(5,6)) , hexToFloat(hex:sub(7,8)) return r,g,b,a end function M.new(data) local map = display.newGroup() local layers = data.layers local tilesets = data.tilesets local width, height = data.width \* data.tilewidth, data.height \* data.tileheight local function gidLookup(gid) -- flipping merged from code by Sergey Lerg local flip = {} flip.x = hasbit(gid, FlippedHorizontallyFlag) flip.y = hasbit(gid, FlippedVerticallyFlag) flip.xy = hasbit(gid, FlippedDiagonallyFlag) gid = clearbit(gid, FlippedHorizontallyFlag) gid = clearbit(gid, FlippedVerticallyFlag) gid = clearbit(gid, FlippedDiagonallyFlag) -- turn a gid into a filename for i = 1, #tilesets do local tileset = tilesets[i] local firstgid = tileset.firstgid local lastgid = firstgid + tileset.tilecount if gid \>= firstgid and gid \<= lastgid then for k,v in pairs(tileset.tiles) do local tile = tileset.tiles[j] if (v.id or tonumber(k)) == (gid - firstgid) then return v.image, flip -- may need updating with documents directory end end end end return false end for i = 1, #layers do local layer = layers[i] layer.properties = layer.properties or {} -- make sure we have a properties table local objectGroup = display.newGroup() if layer.type == "tilelayer" then local item = 0 for j=0, data.height-1 do for i=0, data.width-1 do item = (j \* data.width) + i local tileNumber = layer.data[item] or 0 local gid, flip = gidLookup(tileNumber) if gid then local image = display.newImage(objectGroup, gid, 0, 0) image.anchorX, image.anchorY = 0,1 image.x, image.y = (i-1) \* data.tilewidth, (j+1) \* data.tileheight centerAnchor(image) -- flip it if flip.xy then print("WARNING: Unsupported Tiled rotation x,y in tile ", i,j) else if flip.x then image.xScale = -1 end if flip.y then image.yScale = -1 end end --apply physics if layer.properties.bodyType then physics.addBody(image, layer.properties.bodyType, layer.properties) end -- apply custom properties image = inherit(image, layer.properties) end end end elseif layer.type == "objectgroup" then for j = 1, #layer.objects do local object = layer.objects[j] object.properties = object.properties or {} -- make sure we have a properties table if object.gid then local gid, flip = gidLookup(object.gid) if gid then local image = display.newImageRect(objectGroup, gid, object.width, object.height) -- name and type image.name = object.name image.type = object.type -- apply base properties image.anchorX, image.anchorY = 0, 1 image.x, image.y = object.x, object.y image.rotation = object.rotation image.isVisible = object.visible centerAnchor(image) -- flip it if flip.xy then print("WARNING: Unsupported Tiled rotation x,y in ", object.name) else if flip.x then image.xScale = -1 end if flip.y then image.yScale = -1 end end -- simple phyics if object.properties.bodyType then physics.addBody(image, object.properties.bodyType, object.properties) end -- apply custom properties image = inherit(image, object.properties) image = inherit(image, layer.properties) end else -- if all else fails make a simple rect local rect = display.newRect(0, 0, object.width, object.height) rect.anchorX, rect.anchorY = 0, 0 rect.x, rect.y = object.x, object.y centerAnchor(rect) -- apply custom properties rect = inherit(rect, object.properties) rect = inherit(rect, layer.properties) if rect.fillColor then rect:setFillColor(decodeTiledColor(rect.fillColor)) end if rect.strokeColor then rect:setStrokeColor(decodeTiledColor(rect.strokeColor)) end objectGroup:insert(rect) end end end objectGroup.name = layer.name objectGroup.isVisible = layer.visible objectGroup.alpha = layer.opacity map:insert(objectGroup) end function map:extend(...) local plugins = arg or {} -- each custom object above has its own ponywolf.plugin module for t = 1, #plugins do -- load each module based on type local plugin = require ("com.ponywolf.plugins." .. plugins[t]) -- find each type of tiled object local images = map:listTypes(plugins[t]) if images then -- do we have at least one? for i = 1, #images do -- extend the display object with its own custom code images[i] = plugin.new(images[i]) end end end end -- return first display object with name function map:findObject(name) for layers = self.numChildren,1,-1 do local layer = self[layers] if layer.numChildren then for i = layer.numChildren,1,-1 do if layer[i].name == name then return layer[i] end end end end return false end -- return all display objects with type function map:listTypes(...) local objects = {} for layers = self.numChildren,1,-1 do local layer = self[layers] if layer.numChildren then for i = layer.numChildren,1,-1 do for j = 1, #arg do if arg[j]==nil or layer[i].type == arg[j] then objects[#objects+1] = layer[i] end end end end end return objects end function map:findLayer(name) if self.numChildren then for layers=1, self.numChildren do if self[layers].name==name then -- search layers return self[layers] end end end return false end -- add helpful values to the map itself map.designedWidth, map.designedHeight = width, height return map end return M

If it does, great.

Two, can you post the lines of code around the area of line 126 in ponytiled.lua? I am looking at mine right now and I don’t see the gidLookup function at or near line 126.

If possible, could you zip up the code and post it here?

As for the ssk2 version, @roaminggamer provided me with an example. Take a look and see if there are any differences, although if you are using tiles and not objects, then PonyTiled would be the way to go.

SSK 2 is free now, so it’s no problem that I zip it up, right?

Also, @graham07, you asked me earlier for the solution to a problem I had with PonyTiled.

The problem was my image files, the images in the lua and tmx file generated by Tiled was pointing to the wrong directory. So I changed it manually and it worked!

image = "Lava Cave Scene/lavacavestuff/tile134.png", --\> image = "lavacavestuff/tile134.png"

As Ponytiled  I recommended you follow video tutorials: Using Tiled - Part 1 - Installation and Tiled Basics

I don’t use Pontiled with  latest version of Tiled so I don’t sure it will be work. I use Tiled v0.18.2

@Idurniat: 1.0.1 works fine for me. Also, I don’t think that @graham is having a problem with using Tiled, just using it with Corona. That tutorial does not show much about using it alongside Corona.

@graham: You don’t have to use JSON, just use Lua and you won’t have to worry about decoding, IMHO. Also, I recommend you embed the tileset into the tmx file. When you make your new tileset just check the embed in map option:

This way you don’t have to manage two different files.

You have the line in the code above…

local gid, flip = gidLookup(object.gid)

Whereas I (and PonyWolfs GitHub code) has…

local gid, flip, sheet = gidLookup(tileNumber)

So your version isn’t the latest version (Which may or may not explain anything :slight_smile: My version is the GitHub version.

**EDIT: I should add, I tried to copy/paste your code above, but no joy

Thanks for posting the RG version. That did work, but I suspect its something around my map. I was using a tilesheet so I might try redrawing one in a similar manner as the two loaders did, and see if that helps.

Thank you for your inputs, it’s appreciated.

FYI: Adding an image collection and a quick test worked with the RG version… I will try it with the PonyWolf version later too.

Now maybe I should try Automap to convert the other map :S

Thanks again

Great, so I added 10 tiles to a new map - good - it worked.

I tried to edit the collisions in the editor and now that doesn’t work.(Worked fine as a tilesheet)

Sometimes you have just had enough :slight_smile: - one step forward, 2 steps back!

Ah - I think I just read that you can’t do collisions in a object layer…

Time for plan C… or a beer…

OK, after the beer, I found that if I held the CMD key, it drew the square as needed - it has been a LONG day!

Congrats! I’m glad helped you figure this out. I’m going to be inactive for a few days, going on a family trip.  :wink:

Objects are really inconvenient for me, but if the work for you, no problem!

Update: On a whim, I decided to try it with Dusk… and THAT didn’t work either!

For those that care, I attached the map and tiles to this post.

I did some digging however between a working and not working map file. They appear very different.

Mine:

 \<tile id="137"\> \<objectgroup draworder="index"\> \<object id="1" x="0.0396281" y="0.0792563" width="16.1286" height="2.8136"/\> \<object id="2" x="13.0773" y="2.97211" width="2.85323" height="12.9584"/\> \<object id="3" x="-0.0396281" y="13.1962" width="2.89285" height="2.77397"/\> \</objectgroup\> \</tile\>

A working map

 \<tile id="5"\> \<properties\> \<property name="bodyType" value="static"/\> \<property name="physics:bounce" value="0"/\> \<property name="physics:enabled" value="true"/\> \</properties\> \</tile\>

They are both tile layers.

The JSON looks different too…

Mine:

 "tilesets":[{ "columns":34, "firstgid":1, "image":"tilesheet\_transparent.png", "imageheight":339, "imagewidth":577, "margin":0, "name":"tilesheet\_transparent", "spacing":1, "tilecount":680, "tileheight":16, "tiles": { "136": { "objectgroup": { "draworder":"index", "name":"", "objects":[ { "height":0, "id":4, "name":"", "polyline":[ { "x":0, "y":0 }, { "x":-16.0494, "y":0 }, { "x":-16.0098, "y":15.9305 }, { "x":-13.0773, "y":15.9305 }, { "x":-12.9584, "y":3.01174 }, { "x":0, "y":2.97211 }, { "x":0, "y":-0.0396281 }], "rotation":0, "type":"", "visible":true, "width":0, "x":16.0494, "y":0.0396281 }, { "height":0,

Working map.

"tilesets":[ { "firstgid":1, "image":"..\/graphics\/tileset.png", "imageheight":64, "imagewidth":288, "margin":0, "name":"tileset\_bob", "properties": { }, "spacing":0, "tileheight":32, "tileproperties": { "13": { "bodyType":"static", "physics:bounce":"0", "physics:enabled":"true" }, 

So I half suspect this might not be helping me. I don’t know if I did something wrong creating the map, (continually) or if the new version is causing issues.

OK, last post  :slight_smile: unless there’s an epiphany somewhere…

I lied about Dusk. I *did* get it to work, it was failing on a sprite positioning that I spotted and fixed, so I think I’ll move forward there. 

Thank you for your assistance.

After considerable digging, I came to the conclusion that most (if not all) of these issues may have arisen due to Tiled having a lot of code rewritten, with tile sets being held externally etc. Most of the loaders were written over old versions.

I did get PonyBlitz to load a map quite easily, but even then parts of it got garbled. 

This morning I downgraded Tiled to an old .18 version, threw a map in it and PonyTiled loaded it without an issue… I wish I thought to do that on Saturday morning :slight_smile:

Thought I’d give some closure.

The takeaway here is that the *current* loaders for Tiled may not fully work as intended in the latest V1.x of Tiled. (Admittedly I didn’t use too much of RG’s solution due to lack of examples)

Very strange, 1.0.1 works perfectly for me in PonyTiled.

If I keep everything on an object level it seems to work OK. (This goes against what was in the Tiled videos that were put on).

Later I had issues where even if I used that, the map started getting garbled - weird again.

Once I downgraded Tiled, it’s working fine keeping it all on the Object level, so since that took me days, I don’t want to play with fire :slight_smile:

To note an important point…

Since I’m using Dynamic Shader, I *HAVE* to have separate tiles, so I can’t use a timesheet since the shader required it for lighting. That might be a difference as to why it’s working for you. I believe that separate tiles were what is new in Tiled 1.

So no real issues now I’ve got it moving on the old version and external tiles.

Thanks

Alright, if it works for you, don’t mess with it. But, if you have time, try making a separate project using the newer version of Tiled. You are probably busy, but it’s always good to know why it wasn’t working. 

That’s a pretty cool pixel game you’re making. Where did you get the graphics? Was it from Kenney?

I have similar issues, probably everbody who tries will…

I posted an issue at github: https://github.com/ponywolf/ponytiled/issues/5

Are you choosing to embed the tiles in the project? That seems to be the big change that’s messing with every engine. The artwork needs to be embedded from what I can tell.

Rob