Difference between revisions of "Tiled Bump"

From GiderosMobile
(wip)
 
 
Line 2: Line 2:
  
 
== Description ==
 
== Description ==
Here we will set up Gideros to work with Tiled, Liquidfun being the physics engine.
+
Here we will set up Gideros to work with Tiled with Bump for collision detection.
  
Tiled let you use various layers: ''Tile Layer'', ''Object Layer'', ''Image Layer'', ''Group Layer''.
+
Tiled lets you use various layers: ''Tile Layer'', ''Object Layer'', ''Image Layer'', ''Group Layer''.
  
 
[[File:Tiled Collection of Images Liquidfun.png|480px|Tileset -> Collection of Images]] ''level1 using Collection of Images''
 
[[File:Tiled Collection of Images Liquidfun.png|480px|Tileset -> Collection of Images]] ''level1 using Collection of Images''
Line 15: Line 15:
 
This is how you could load your Tiled maps in Gideros:
 
This is how you could load your Tiled maps in Gideros:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
local currlevel = TiledLevels.new(pathtotiledlevel, ecs, liquidfun, layers)
+
local currlevel = TiledLevels.new(pathtotiledlevel, ecs, bump, layers)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 24: Line 24:
 
function LevelX:init()
 
function LevelX:init()
 
application:setBackgroundColor(0x5500ff)
 
application:setBackgroundColor(0x5500ff)
-- plugins
+
-- move the cursor out of the way (more annoying than usefull?!)
 +
if not application:isPlayerMode() then
 +
local sw, sh = application:get("screenSize") -- the user's screen size!
 +
application:set("cursorPosition", sw-10, sh-10) -- 0, 0
 +
end
 +
-- _____  _    _    _  _____ _____ _  _  _____
 +
--|  __ \| |  | |  | |/ ____|_  _| \ | |/ ____|
 +
--| |__) | |  | |  | | |  __  | | |  \| | (___ 
 +
--|  ___/| |  | |  | | | |_ | | | | . ` |\___ \
 +
--| |    | |___| |__| | |__| |_| |_| |\  |____) |
 +
--|_|    |______\____/ \_____|_____|_| \_|_____/
 
-- tiny-ecs
 
-- tiny-ecs
 
self.tiny = require "classes/tiny-ecs"
 
self.tiny = require "classes/tiny-ecs"
 
self.tiny.tworld = self.tiny.world()
 
self.tiny.tworld = self.tiny.world()
-- liquidfun
+
-- cbump (bworld)
local bworld = b2.World.new(0, 20, true) -- gravity x, gravity y, doSleep?
+
local bump = require "cbump"
-- layers
+
local bworld = bump.newWorld() -- grid cell size, default = 64
 +
-- _          __    ________ _____  _____
 +
--| |        /\\ \  / /  ____|  __ \ / ____|
 +
--| |      /  \\ \_/ /| |__  | |__) | (___ 
 +
--| |      / /\ \\  / |  __| |  _  / \___ \
 +
--| |____ / ____ \| |  | |____| | \ \ ____) |
 +
--|______/_/    \_\_|  |______|_|  \_\_____/
 
local layers = {}
 
local layers = {}
 
layers["main"] = Sprite.new() -- one Sprite to hold them all
 
layers["main"] = Sprite.new() -- one Sprite to hold them all
Line 37: Line 53:
 
layers["fg"] = Sprite.new() -- fg layer
 
layers["fg"] = Sprite.new() -- fg layer
 
layers["player1input"] = Sprite.new() -- player1 input layer
 
layers["player1input"] = Sprite.new() -- player1 input layer
-- levels
+
-- _      ________      ________ _      _____
 +
--| |    |  ____\ \    / /  ____| |    / ____|
 +
--| |    | |__  \ \  / /| |__  | |    | (___ 
 +
--| |    |  __|  \ \/ / |  __| | |    \___ \
 +
--| |____| |____  \  /  | |____| |____ ____) |
 +
--|______|______|  \/  |______|______|_____/
 
self.tiledlevels = {}
 
self.tiledlevels = {}
 
self.tiledlevels[1] = "tiled/levels/level01" -- lua file without extension
 
self.tiledlevels[1] = "tiled/levels/level01" -- lua file without extension
Line 54: Line 75:
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 
-- ...
 
-- ...
-- global vars
+
-- global variables
 
g_currlevel = 1 -- 1 = Collection of Images, 2 = Tileset
 
g_currlevel = 1 -- 1 = Collection of Images, 2 = Tileset
g_keyleft = KeyCode.LEFT -- player1 left
+
g_keyleft = KeyCode.LEFT
g_keyright = KeyCode.RIGHT -- player1 right
+
g_keyright = KeyCode.RIGHT
g_keyup = KeyCode.UP -- player1 up
+
g_keyup = KeyCode.UP
 
-- ...
 
-- ...
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 76: Line 97:
 
The Tiled layers are split in two categories:
 
The Tiled layers are split in two categories:
 
* '''deco layers''' for displaying images and shapes on the screen
 
* '''deco layers''' for displaying images and shapes on the screen
* '''physics layers''' consisting of shapes used for physics collisions
+
* '''physics layers''' consisting of only '''Rectangles''' used for physics collisions
  
 
  '''note''': the layers names in the code correspond to the layers names in Tiled
 
  '''note''': the layers names in the code correspond to the layers names in Tiled
  
Tiled Shapes can be both for decoration and physics. For the shapes which are decorative we call the ''buildShapes'' function and for the shapes which are for physics we call the ''buildLFShapes'' function.
+
For the shapes which are decorative we call the ''buildShapes'' function.
  
 
Finally, each shapes functions will call the appropriate Class to build the shape (Ellipse, Point, Polygon, Polyline, Rectangle, Text).
 
Finally, each shapes functions will call the appropriate Class to build the shape (Ellipse, Point, Polygon, Polyline, Rectangle, Text).
Line 92: Line 113:
 
function TiledLevels:init(tmpath, xtiny, xbworld, xlayers)
 
function TiledLevels:init(tmpath, xtiny, xbworld, xlayers)
 
local myformat = TextureBase.RGBA4444 -- perfs? XXX
 
local myformat = TextureBase.RGBA4444 -- perfs? XXX
self.world = xbworld
 
 
local tm = require(tmpath) -- eg.: "tiled/test" without ".lua" extension + exclude from execution!
 
local tm = require(tmpath) -- eg.: "tiled/test" without ".lua" extension + exclude from execution!
 
local tsimgpath -- "tiled/", Tiled root path to images
 
local tsimgpath -- "tiled/", Tiled root path to images
Line 105: Line 125:
 
--  | |  _| |_| |____| |____ ____) | |____  | |   
 
--  | |  _| |_| |____| |____ ____) | |____  | |   
 
--  |_|  |_____|______|______|_____/|______|  |_|   
 
--  |_|  |_____|______|______|_____/|______|  |_|   
-- this is the classic
+
-- this is the classic "Tileset"
 
for i = 1, #tm.tilesets do
 
for i = 1, #tm.tilesets do
 
local tileset = tm.tilesets[i]
 
local tileset = tm.tilesets[i]
Line 124: Line 144:
 
end
 
end
 
end
 
end
-- classic tileset function
+
-- classic "Tileset" function
 
local function gid2tileset(tm, gid)
 
local function gid2tileset(tm, gid)
 
for i = 1, #tm.tilesets do
 
for i = 1, #tm.tilesets do
Line 147: Line 167:
 
-- _| |_| |  | |/ ____ \ |__| | |____ ____) |
 
-- _| |_| |  | |/ ____ \ |__| | |____ ____) |
 
--|_____|_|  |_/_/    \_\_____|______|_____/  
 
--|_____|_|  |_/_/    \_\_____|______|_____/  
-- this one parses individual images
+
-- this one parses individual images "Collection of Images"
 
local tilesetimages = {} -- table holding all the tileset images info (path, width, height)
 
local tilesetimages = {} -- table holding all the tileset images info (path, width, height)
 
for i = 1, #tm.tilesets do
 
for i = 1, #tm.tilesets do
Line 219: Line 239:
 
--  | |  _| |_| |____| |____| |____ / ____ \| |  | |____| | \ \  
 
--  | |  _| |_| |____| |____| |____ / ____ \| |  | |____| | \ \  
 
--  |_|  |_____|______|______|______/_/    \_\_|  |______|_|  \_\
 
--  |_|  |_____|______|______|______/_/    \_\_|  |______|_|  \_\
-- this is the classic tile layers
+
-- this is the classic "Tileset" tile layers
-- please name your layers accordingly (background = bg, foreground = fg)
+
-- background = bg, foreground = fg
 
if layer.type == "tilelayer" and (layer.name:match("bg") or layer.name:match("fg")) then
 
if layer.type == "tilelayer" and (layer.name:match("bg") or layer.name:match("fg")) then
 
if layer.name:match("bg") then group = xlayers["bg"]
 
if layer.name:match("bg") then group = xlayers["bg"]
Line 258: Line 278:
 
--| |__| | |_) | |__| | |___| |____  | |  | |____ / ____ \| |  | |____| | \ \  
 
--| |__| | |_) | |__| | |___| |____  | |  | |____ / ____ \| |  | |____| | \ \  
 
-- \____/|____/ \____/|______\_____|  |_|  |______/_/    \_\_|  |______|_|  \_\
 
-- \____/|____/ \____/|______\_____|  |_|  |______/_/    \_\_|  |______|_|  \_\
-- objects layers can be for decoration shapes or any physics shapes (cbump, liquidfun)
+
-- objects layers can be for decoration (images and shapes) and physics (Bump)
 
elseif layer.type == "objectgroup" then
 
elseif layer.type == "objectgroup" then
 
local o
 
local o
Line 284: Line 304:
 
myshape, mytable = nil, nil
 
myshape, mytable = nil, nil
 
local color = math.random(0xffffff)
 
local color = math.random(0xffffff)
local tex = "gfx/textures/wdipagu_2K_Albedo.jpg_0007.png"
+
local shapelinecolor = 0xffffff
 +
if o.shape == "point" then
 +
shapelinecolor = math.random(0xffffff)
 +
end
 
mytable = {
 
mytable = {
shapelinewidth=1, shapelinecolor=color,
+
shapelinewidth=1, shapelinecolor=shapelinecolor,
texpath=tex, istexpot=true, scalex=1,
 
 
color=color,
 
color=color,
 
}
 
}
Line 301: Line 323:
 
myshape, mytable = nil, nil
 
myshape, mytable = nil, nil
 
local color = math.random(0xffffff)
 
local color = math.random(0xffffff)
local tex = "gfx/textures/wdipagu_2K_Albedo.jpg_0007.png"
+
local shapelinecolor = 0xffffff
 +
if o.shape == "point" then
 +
shapelinecolor = math.random(0xffffff)
 +
end
 
mytable = {
 
mytable = {
shapelinewidth=3, shapelinecolor=color,
+
shapelinewidth=1, shapelinecolor=shapelinecolor,
texpath=tex, istexpot=true, scalex=1,
 
 
color=color,
 
color=color,
 
}
 
}
Line 321: Line 345:
 
--| |          __/ |                          __/ |               
 
--| |          __/ |                          __/ |               
 
--|_|          |___/                          |___/               
 
--|_|          |___/                          |___/               
-- add a physics body to the shapes (cbump, liquidfun)
+
-- add a physics body to the shapes (Bump)
elseif layer.name == "physics_grounds" then
+
elseif layer.name:match("physics_grounds") then
 
for i = 1, #layer.objects do
 
for i = 1, #layer.objects do
 
o = layer.objects[i]
 
o = layer.objects[i]
o.isfloor = true
+
o.isfloor = true -- Bump id
-- liquidfun
+
-- physics body
local mylftable = {
+
xbworld:add(o, o.x, o.y, o.width, o.height)
density=1, restitution=0, friction=1,
+
-- decor (optional)
BIT=G_BITSOLID, COLBIT=solidcollisions, ROLE=G_GROUND,
+
if g_currlevel == 1 then
}
+
local texpath = "gfx/textures/wdipagu_2K_Albedo.jpg_0007.png"
self:buildLFShapes(o, mylftable)
 
-- graphics
 
if g_currlevel == 1 then -- only for 1st level (Collection of Images)
 
local tex = "gfx/textures/wdipagu_2K_Albedo.jpg_0007.png"
 
 
mytable = {
 
mytable = {
texpath=tex, istexpot=true, scalex=1.4,
+
texpath=texpath, istexpot=true, scalex=1,
r=8*32/255, g=8*32/255, b=5.5*32/255,
 
alpha=8*32/255,
 
 
}
 
}
 
levelsetup = {}
 
levelsetup = {}
Line 358: Line 376:
 
local opos = vector(o.x, o.y)
 
local opos = vector(o.x, o.y)
 
-- EPlayer1:init(xspritelayer, xpos)
 
-- EPlayer1:init(xspritelayer, xpos)
self.player1 = EPlayer1.new(self.world, xlayers["actors"], opos)
+
self.player1 = EPlayer1.new(xlayers["actors"], opos)
 
xtiny.tworld:addEntity(self.player1)
 
xtiny.tworld:addEntity(self.player1)
 +
-- physics body
 +
xbworld:add(
 +
self.player1,
 +
self.player1.pos.x, self.player1.pos.y,
 +
self.player1.collbox.w, self.player1.collbox.h
 +
)
 
end
 
end
 
end
 
end
Line 422: Line 446:
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_Shape_Text.new(tablebase)
 
myshape = Tiled_Shape_Text.new(tablebase)
else
 
print("*** CANNOT PROCESS THIS SHAPE! ***", xobject.shape, xobject.name)
 
return
 
end
 
 
return myshape
 
end
 
 
-- physics shapes
 
function TiledLevels:buildLFShapes(xobject, xlevelsetup)
 
local myshape -- Tiled shapes: ellipse, point, polygon, polyline, rectangle
 
local tablebase = {}
 
if xobject.shape == "ellipse" then
 
tablebase = {
 
x = xobject.x, y = xobject.y,
 
w = xobject.width, h = xobject.height, rotation = xobject.rotation,
 
}
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_LF_Shape_Ellipse.new(self.world, tablebase)
 
elseif xobject.shape == "point" then
 
tablebase = {
 
x = xobject.x, y = xobject.y,
 
w = xobject.width, h = xobject.height, rotation = xobject.rotation, -- w and h = 0
 
}
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_LF_Shape_Point.new(self.world, tablebase)
 
elseif xobject.shape == "polygon" then
 
tablebase = {
 
x = xobject.x, y = xobject.y,
 
coords = xobject.polygon, rotation = xobject.rotation,
 
}
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_LF_Shape_Polygon.new(self.world, tablebase)
 
elseif xobject.shape == "polyline" then
 
tablebase = {
 
x = xobject.x, y = xobject.y,
 
coords = xobject.polyline, rotation = xobject.rotation,
 
}
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_LF_Shape_Polyline.new(self.world, tablebase)
 
elseif xobject.shape == "rectangle" then
 
tablebase = {
 
x = xobject.x, y = xobject.y,
 
w = xobject.width, h = xobject.height, rotation = xobject.rotation,
 
}
 
for k, v in pairs(xlevelsetup) do tablebase[k] = v end
 
myshape = Tiled_LF_Shape_Rectangle.new(self.world, tablebase)
 
 
else
 
else
 
print("*** CANNOT PROCESS THIS SHAPE! ***", xobject.shape, xobject.name)
 
print("*** CANNOT PROCESS THIS SHAPE! ***", xobject.shape, xobject.name)
Line 784: Line 761:
 
-- self.w, self.h = img:getWidth(), img:getHeight()
 
-- self.w, self.h = img:getWidth(), img:getHeight()
 
self:addChild(img)
 
self:addChild(img)
end
 
</syntaxhighlight>
 
 
== TILED PHYSICS SHAPES ==
 
Here are the Classes to build the Tiled physics shapes (you may want to put each physics shape in separate files).
 
<syntaxhighlight lang="lua">
 
Tiled_LF_Shape_Ellipse = Core.class(Sprite)
 
 
function Tiled_LF_Shape_Ellipse:init(xworld, xparams)
 
-- params
 
local params = xparams or {}
 
params.x = xparams.x or nil
 
params.y = xparams.y or nil
 
params.w = xparams.w or nil
 
params.h = xparams.h or nil
 
params.steps = xparams.steps or 32 -- 24
 
params.rotation = xparams.rotation or 0
 
params.type = xparams.type or nil -- default (nil) = b2.STATIC_BODY
 
params.fixedrotation = xparams.fixedrotation or (xparams.fixedrotation == nil) -- default to true
 
params.density = xparams.density or 0
 
params.restitution = xparams.restitution or nil
 
params.friction = xparams.friction or nil
 
params.gravityscale = xparams.gravityscale or 1
 
params.BIT = xparams.BIT or nil
 
params.COLBIT = xparams.COLBIT or nil
 
params.ROLE = xparams.ROLE or nil
 
params.data = xparams.data or nil
 
-- the others
 
self.x = params.x
 
self.y = params.y
 
-- self.w = params.w
 
-- self.h = params.h
 
-- self.rotation = params.rotation
 
-- self.BIT = params.BIT
 
-- self.COLBIT = params.COLBIT
 
-- body, b2.STATIC_BODY, b2.KINEMATIC_BODY, b2.DYNAMIC_BODY
 
self.body = xworld:createBody { type = params.type }
 
self.body:setGravityScale(params.gravityscale)
 
self.body.role = params.ROLE
 
self.body.isdirty = false
 
self.body:setFixedRotation(params.fixedrotation)
 
self.body:setAngle(^<params.rotation)
 
self.body:setPosition(self.x, self.y)
 
-- self.body.img = self.img
 
self.body.data = params.data
 
-- the shape
 
local shape
 
local sin, cos = math.sin, math.cos
 
if params.w ~= params.h then -- oval
 
local cs = {}
 
for i = 0, 360, 360 / params.steps  do
 
cs[#cs + 1] = (params.w / 2) + params.w / 2 * cos(^<i)
 
cs[#cs + 1] = (params.h / 2) + params.h / 2 * sin(^<i)
 
end
 
shape = b2.ChainShape.new()
 
shape:createLoop(unpack(cs))
 
else -- circle
 
local hypo = params.w/2 + params.h/2
 
shape = b2.CircleShape.new(hypo/2, hypo/2, params.w/2) -- (centerx, centery, radius)
 
end
 
-- fixture
 
local fixture = self.body:createFixture {
 
shape=shape, density=params.density, restitution=params.restitution, friction=params.friction,
 
}
 
-- filter data
 
if params.BIT == G_BITSENSOR then fixture:setSensor(true) end
 
local filterData = { categoryBits=params.BIT, maskBits=params.COLBIT, groupIndex=0, }
 
fixture:setFilterData(filterData)
 
-- clean up?
 
filterData = {} -- nil
 
fixture = nil
 
shape = nil
 
end
 
 
Tiled_LF_Shape_Point = Core.class(Sprite)
 
 
function Tiled_LF_Shape_Point:init(xworld, xparams)
 
-- params
 
local params = xparams or {}
 
params.x = xparams.x or nil
 
params.y = xparams.y or nil
 
params.w = xparams.w or nil
 
params.h = xparams.h or nil
 
params.rotation = xparams.rotation or 0
 
params.type = xparams.type or nil -- default (nil) = b2.STATIC_BODY
 
params.fixedrotation = xparams.fixedrotation or (xparams.fixedrotation == nil) -- default to true
 
params.density = xparams.density or nil
 
params.restitution = xparams.restitution or nil
 
params.friction = xparams.friction or nil
 
params.gravityscale = xparams.gravityscale or 1
 
params.BIT = xparams.BIT or nil
 
params.COLBIT = xparams.COLBIT or nil
 
params.ROLE = xparams.ROLE or nil
 
params.data = xparams.data or nil
 
-- the others
 
self.x = params.x
 
self.y = params.y
 
-- self.w = params.w
 
-- self.h = params.h
 
-- self.rotation = params.rotation
 
-- self.BIT = params.BIT
 
-- self.COLBIT = params.COLBIT
 
-- body, b2.STATIC_BODY, b2.KINEMATIC_BODY, b2.DYNAMIC_BODY
 
self.body = xworld:createBody { type=params.type }
 
self.body:setGravityScale(params.gravityscale)
 
self.body.role = params.ROLE
 
self.body.isdirty = false
 
self.body:setFixedRotation(params.fixedrotation)
 
self.body:setAngle(^<params.rotation)
 
self.body:setPosition(self.x, self.y)
 
-- self.body.img = self.img
 
self.body.data = params.data
 
-- the shape
 
local hypo = 1
 
local shape = b2.CircleShape.new(hypo/2, hypo/2, hypo) -- (centerx, centery, radius)
 
-- the fixture
 
local fixture = self.body:createFixture {
 
shape=shape, density=params.density, restitution=params.restitution, friction=params.friction,
 
}
 
-- filter data
 
if params.BIT == G_BITSENSOR then fixture:setSensor(true) end
 
local filterData = { categoryBits=params.BIT, maskBits=params.COLBIT, groupIndex=0, }
 
fixture:setFilterData(filterData)
 
-- clean up?
 
filterData = {} -- nil
 
fixture = nil
 
shape = nil
 
end
 
 
Tiled_LF_Shape_Polygon = Core.class(Sprite)
 
 
function Tiled_LF_Shape_Polygon:init(xworld, xparams)
 
-- params
 
local params = xparams or {}
 
params.x = xparams.x or nil
 
params.y = xparams.y or nil
 
params.w = xparams.w or nil
 
params.h = xparams.h or nil
 
params.coords = xparams.coords or nil
 
params.rotation = xparams.rotation or 0
 
params.type = xparams.type or nil -- default (nil) = b2.STATIC_BODY
 
params.fixedrotation = xparams.fixedrotation or (xparams.fixedrotation == nil) -- default to true
 
params.density = xparams.density or nil
 
params.restitution = xparams.restitution or nil
 
params.friction = xparams.friction or nil
 
params.gravityscale = xparams.gravityscale or 1
 
params.BIT = xparams.BIT or nil
 
params.COLBIT = xparams.COLBIT or nil
 
params.ROLE = xparams.ROLE or nil
 
params.data = xparams.data or nil
 
-- the others
 
self.x = params.x
 
self.y = params.y
 
-- self.w = params.w
 
-- self.h = params.h
 
-- self.rotation = params.rotation
 
-- self.BIT = params.BIT
 
-- self.COLBIT = params.COLBIT
 
-- body, b2.STATIC_BODY, b2.KINEMATIC_BODY, b2.DYNAMIC_BODY
 
self.body = xworld:createBody { type=params.type }
 
self.body:setGravityScale(params.gravityscale)
 
self.body.role = params.ROLE
 
self.body.isdirty = false
 
self.body:setFixedRotation(params.fixedrotation)
 
self.body:setAngle(^<params.rotation)
 
self.body:setPosition(self.x, self.y)
 
-- self.body.img = self.img
 
self.body.data = params.data
 
-- the shape
 
local shape
 
local cs = {}
 
for c = 1, #params.coords do
 
cs[#cs+1] = params.coords[c].x
 
cs[#cs+1] = params.coords[c].y
 
end
 
if #params.coords == 2 then -- this is a line
 
shape = b2.EdgeShape.new(cs[1], cs[2], cs[3], cs[4])
 
else -- this is a polygon
 
shape = b2.ChainShape.new()
 
shape:createLoop(unpack(cs))
 
end
 
-- the fixture
 
local fixture = self.body:createFixture {
 
shape=shape, density=params.density, restitution=params.restitution, friction=params.friction,
 
}
 
-- filter data
 
if params.BIT == G_BITSENSOR then fixture:setSensor(true) end
 
local filterData = { categoryBits=params.BIT, maskBits=params.COLBIT, groupIndex=0, }
 
fixture:setFilterData(filterData)
 
-- clean up?
 
filterData = {} -- nil
 
fixture = nil
 
cs = {} -- nil
 
shape = nil
 
end
 
 
Tiled_LF_Shape_Polyline = Core.class(Sprite)
 
 
function Tiled_LF_Shape_Polyline:init(xworld, xparams)
 
-- params
 
local params = xparams or {}
 
params.x = xparams.x or nil
 
params.y = xparams.y or nil
 
params.w = xparams.w or nil
 
params.h = xparams.h or nil
 
params.coords = xparams.coords or nil
 
params.rotation = xparams.rotation or 0
 
params.type = xparams.type or nil -- default (nil) = b2.STATIC_BODY
 
params.fixedrotation = xparams.fixedrotation or (xparams.fixedrotation == nil) -- default to true
 
params.density = xparams.density or nil
 
params.restitution = xparams.restitution or nil
 
params.friction = xparams.friction or nil
 
params.gravityscale = xparams.gravityscale or 1
 
params.BIT = xparams.BIT or nil
 
params.COLBIT = xparams.COLBIT or nil
 
params.ROLE = xparams.ROLE or nil
 
params.data = xparams.data or nil
 
-- the others
 
self.x = params.x
 
self.y = params.y
 
-- self.w = params.w
 
-- self.h = params.h
 
-- self.rotation = params.rotation
 
-- self.BIT = params.BIT
 
-- self.COLBIT = params.COLBIT
 
-- body, b2.STATIC_BODY, b2.KINEMATIC_BODY, b2.DYNAMIC_BODY
 
self.body = xworld:createBody { type=params.type }
 
self.body:setGravityScale(params.gravityscale)
 
self.body.role = params.ROLE
 
self.body.isdirty = false
 
self.body:setFixedRotation(params.fixedrotation)
 
self.body:setAngle(^<params.rotation)
 
self.body:setPosition(self.x, self.y)
 
-- self.body.img = self.img
 
self.body.data = params.data
 
-- the shape
 
local shape
 
local cs = {}
 
for c = 1, #params.coords do
 
cs[#cs+1] = params.coords[c].x
 
cs[#cs+1] = params.coords[c].y
 
end
 
if #params.coords == 2 then -- this is a line
 
shape = b2.EdgeShape.new(cs[1], cs[2], cs[3], cs[4])
 
else -- this is a polyline
 
shape = b2.ChainShape.new()
 
shape:createChain(unpack(cs))
 
end
 
-- the fixture
 
local fixture = self.body:createFixture {
 
shape=shape, density=params.density, restitution=params.restitution, friction=params.friction,
 
}
 
-- filter data
 
if params.BIT == G_BITSENSOR then fixture:setSensor(true) end
 
local filterData = { categoryBits=params.BIT, maskBits=params.COLBIT, groupIndex=0, }
 
fixture:setFilterData(filterData)
 
-- clean up?
 
filterData = {} -- nil
 
fixture = nil
 
cs = {} -- nil
 
shape = nil
 
end
 
 
Tiled_LF_Shape_Rectangle = Core.class(Sprite)
 
 
function Tiled_LF_Shape_Rectangle:init(xworld, xparams)
 
-- params
 
local params = xparams or {}
 
params.x = xparams.x or nil
 
params.y = xparams.y or nil
 
params.w = xparams.w or nil
 
params.h = xparams.h or nil
 
params.rotation = xparams.rotation or 0
 
params.type = xparams.type or nil -- default (nil) = b2.STATIC_BODY
 
params.fixedrotation = xparams.fixedrotation or (xparams.fixedrotation == nil) -- default to true
 
params.density = xparams.density or nil
 
params.restitution = xparams.restitution or nil
 
params.friction = xparams.friction or nil
 
params.gravityscale = xparams.gravityscale or 1
 
params.BIT = xparams.BIT or nil
 
params.COLBIT = xparams.COLBIT or nil
 
params.ROLE = xparams.ROLE or nil
 
params.data = xparams.data or nil
 
-- the others
 
self.x = params.x
 
self.y = params.y
 
-- self.w = params.w
 
-- self.h = params.h
 
-- self.rotation = params.rotation
 
-- self.BIT = params.BIT
 
-- self.COLBIT = params.COLBIT
 
-- body, b2.STATIC_BODY, b2.KINEMATIC_BODY, b2.DYNAMIC_BODY
 
self.body = xworld:createBody { type=params.type }
 
self.body:setGravityScale(params.gravityscale)
 
self.body.role = params.ROLE
 
self.body.isdirty = false
 
self.body:setFixedRotation(params.fixedrotation)
 
self.body:setAngle(^<params.rotation)
 
self.body:setPosition(self.x, self.y)
 
-- self.body.img = self.img
 
self.body.data = params.data
 
-- the shape
 
local shape = b2.PolygonShape.new()
 
shape:setAsBox(
 
params.w/2, params.h/2, -- half w, half h
 
params.w/2, params.h/2, -- centerx, centery
 
0) -- rotation
 
-- the fixture
 
local fixture = self.body:createFixture {
 
shape=shape, density=params.density, restitution=params.restitution, friction=params.friction,
 
}
 
-- filter data
 
if params.BIT == G_BITSENSOR then fixture:setSensor(true) end
 
local filterData = { categoryBits=params.BIT, maskBits=params.COLBIT, groupIndex=0, }
 
fixture:setFilterData(filterData)
 
-- clean up?
 
filterData = {} -- nil
 
fixture = nil
 
shape = nil
 
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
== DEMO PROJECT ==
 
== DEMO PROJECT ==
'''[[Media:Tiled demo lf.zip]]''' ('''tip''': right click -> Save Link As)
+
'''[[Media:Tiled demo bump.zip]]''' ('''tip''': right click -> Save Link As)
  
  
 
'''[[Tiled]]'''
 
'''[[Tiled]]'''
 
{{GIDEROS IMPORTANT LINKS}}
 
{{GIDEROS IMPORTANT LINKS}}

Latest revision as of 17:36, 17 May 2025

Description

Here we will set up Gideros to work with Tiled with Bump for collision detection.

Tiled lets you use various layers: Tile Layer, Object Layer, Image Layer, Group Layer.

Tileset -> Collection of Images level1 using Collection of Images

Tileset -> Based on Tileset Image level2 using Tileset Image

full demo available at the end!

LOAD YOUR TILED MAP

This is how you could load your Tiled maps in Gideros:

local currlevel = TiledLevels.new(pathtotiledlevel, ecs, bump, layers)

An excerpt from the demo project where we call the TiledLevels Class:

LevelX = Core.class(Sprite)

function LevelX:init()
	application:setBackgroundColor(0x5500ff)
	-- move the cursor out of the way (more annoying than usefull?!)
	if not application:isPlayerMode() then
		local sw, sh = application:get("screenSize") -- the user's screen size!
		application:set("cursorPosition", sw-10, sh-10) -- 0, 0
	end
	-- _____  _     _    _  _____ _____ _   _  _____ 
	--|  __ \| |   | |  | |/ ____|_   _| \ | |/ ____|
	--| |__) | |   | |  | | |  __  | | |  \| | (___  
	--|  ___/| |   | |  | | | |_ | | | | . ` |\___ \ 
	--| |    | |___| |__| | |__| |_| |_| |\  |____) |
	--|_|    |______\____/ \_____|_____|_| \_|_____/ 
	-- tiny-ecs
	self.tiny = require "classes/tiny-ecs"
	self.tiny.tworld = self.tiny.world()
	-- cbump (bworld)
	local bump = require "cbump"
	local bworld = bump.newWorld() -- grid cell size, default = 64
	-- _           __     ________ _____   _____ 
	--| |        /\\ \   / /  ____|  __ \ / ____|
	--| |       /  \\ \_/ /| |__  | |__) | (___  
	--| |      / /\ \\   / |  __| |  _  / \___ \ 
	--| |____ / ____ \| |  | |____| | \ \ ____) |
	--|______/_/    \_\_|  |______|_|  \_\_____/ 
	local layers = {}
	layers["main"] = Sprite.new() -- one Sprite to hold them all
	layers["bg"] = Sprite.new() -- bg layer
	layers["actors"] = Sprite.new() -- actors layer
	layers["fg"] = Sprite.new() -- fg layer
	layers["player1input"] = Sprite.new() -- player1 input layer
	-- _      ________      ________ _       _____ 
	--| |    |  ____\ \    / /  ____| |     / ____|
	--| |    | |__   \ \  / /| |__  | |    | (___  
	--| |    |  __|   \ \/ / |  __| | |     \___ \ 
	--| |____| |____   \  /  | |____| |____ ____) |
	--|______|______|   \/   |______|______|_____/ 
	self.tiledlevels = {}
	self.tiledlevels[1] = "tiled/levels/level01" -- lua file without extension
	self.tiledlevels[2] = "tiled/levels/level02" -- lua file without extension
	-- ...
	-- here we build the level using Tiled
	local currlevel = TiledLevels.new(self.tiledlevels[g_currlevel], self.tiny, bworld, layers)
	-- ...

g_currlevel is a global variable declared in the "main.lua" file. The demo project has currently 2 Tiled levels available:

  • g_currlevel = 1, level built using Tiled: New Tileset -> Collection of Images
  • g_currlevel = 2, level built using Tiled: New Tileset -> Based on Tileset Image

main.lua:

-- ...
-- global variables
g_currlevel = 1 -- 1 = Collection of Images, 2 = Tileset
g_keyleft = KeyCode.LEFT
g_keyright = KeyCode.RIGHT
g_keyup = KeyCode.UP
-- ...

Below is the TiledLevels Class.

BUILD YOUR LEVEL

The TiledLevels Class will read a Tiled lua file and build the level in Gideros.

There are a couple of steps before building the level:

  1. we need to link the Tiled Tileset images to their correct tile id
  2. optionally it is best (performance wise) to pack the images
  3. we create a parseImage function for each Tiled layers to call

We can then read each Tiled Layers and build our levels (deco layers and physics layers).

The Tiled layers are split in two categories:

  • deco layers for displaying images and shapes on the screen
  • physics layers consisting of only Rectangles used for physics collisions
note: the layers names in the code correspond to the layers names in Tiled

For the shapes which are decorative we call the buildShapes function.

Finally, each shapes functions will call the appropriate Class to build the shape (Ellipse, Point, Polygon, Polyline, Rectangle, Text).

You will find below the steps implemented in the TiledLevels Class.

BUILD YOUR LEVEL FULL CODE

TiledLevels = Core.class(Sprite)

function TiledLevels:init(tmpath, xtiny, xbworld, xlayers)
	local myformat = TextureBase.RGBA4444 -- perfs? XXX
	local tm = require(tmpath) -- eg.: "tiled/test" without ".lua" extension + exclude from execution!
	local tsimgpath -- "tiled/", Tiled root path to images
	if g_currlevel == 1 then tsimgpath = "tiled/levels/" -- level01
	elseif g_currlevel == 2 then tsimgpath = "tiled/levels/" -- level02
	-- ...
	end
	-- _______ _____ _      ______  _____ ______ _______ 
	--|__   __|_   _| |    |  ____|/ ____|  ____|__   __|
	--   | |    | | | |    | |__  | (___ | |__     | |   
	--   | |    | | | |    |  __|  \___ \|  __|    | |   
	--   | |   _| |_| |____| |____ ____) | |____   | |   
	--   |_|  |_____|______|______|_____/|______|  |_|   
	-- this is the classic "Tileset"
	for i = 1, #tm.tilesets do
		local tileset = tm.tilesets[i]
		-- add extra values (variables) to a tm.tilesets[i] table
		if tileset.image then -- only tileset tilemap layers
			tileset.numcols = math.floor(
				(tileset.imagewidth-tileset.margin+tileset.spacing)/
				(tileset.tilewidth+tileset.spacing)
			)
			tileset.numrows = math.floor(
				(tileset.imageheight-tileset.margin+tileset.spacing)/
				(tileset.tileheight+tileset.spacing)
			)
			tileset.lastgid = tileset.firstgid+(tileset.numcols*tileset.numrows)-1
			tileset.texture = Texture.new(tsimgpath..tileset.image, false,
				{ format=myformat, extend=false, } -- extend=false, true
			)
		end
	end
	-- classic "Tileset" function
	local function gid2tileset(tm, gid)
		for i = 1, #tm.tilesets do
			local tileset = tm.tilesets[i]
			if tileset.image then -- only valid tileset layers
				if tileset.firstgid <= gid and gid <= tileset.lastgid then
					return tileset
				end
			end
		end
	end
	-- _______ _____ _      ______  _____ ______ _______ 
	--|__   __|_   _| |    |  ____|/ ____|  ____|__   __|
	--   | |    | | | |    | |__  | (___ | |__     | |   
	--   | |    | | | |    |  __|  \___ \|  __|    | |   
	--   | |   _| |_| |____| |____ ____) | |____   | |   
	--   |_|  |_____|______|______|_____/|______|  |_|   
	-- _____ __  __          _____ ______  _____ 
	--|_   _|  \/  |   /\   / ____|  ____|/ ____|
	--  | | | \  / |  /  \ | |  __| |__  | (___  
	--  | | | |\/| | / /\ \| | |_ |  __|  \___ \ 
	-- _| |_| |  | |/ ____ \ |__| | |____ ____) |
	--|_____|_|  |_/_/    \_\_____|______|_____/ 
	-- this one parses individual images "Collection of Images"
	local tilesetimages = {} -- table holding all the tileset images info (path, width, height)
	for i = 1, #tm.tilesets do
		local tileset = tm.tilesets[i]
		if not tileset.image then -- filter out tileset tilemap layers, only tileset images
			local tiles = tileset.tiles
			for j = 1, #tiles do
				-- populate the tilesetimages table based on the tile gid and id
				-- note: you may have to adjust the path (tsimgpath) to point to the image folder
				tilesetimages[tileset.firstgid + tiles[j].id] = {
					path=tsimgpath..tiles[j].image,
					width=tiles[j].width,
					height=tiles[j].height,
				}
			end
		end
	end
--[[
	-- this function is if you don't want to pack your Tiled images even though you should!
	local function parseImage(xobject, xlayer)
		local tex = Texture.new(tilesetimages[xobject.gid].path, false,
			{ format=myformat , extend=false, } -- extend=false, true
		)
		local bitmap = Bitmap.new(tex)
		bitmap:setAnchorPoint(0, 1) -- because I always forget to modify Tiled objects alignment
		-- supports Tiled image scaling
		local scalex, scaley = xobject.width/tex:getWidth(), xobject.height/tex:getHeight()
		bitmap:setScale(scalex, scaley)
		bitmap:setRotation(xobject.rotation)
		bitmap:setPosition(xobject.x, xobject.y)
		xlayer:addChild(bitmap)
	end
]]
	-- pack all the images for perfs (TexturePack)
	local tpt = {} -- texture pack table
	for i = 1, #tm.layers do
		local layer = tm.layers[i]
		if layer.name:match("bg_deco_images") or layer.name:match("fg_deco_images") then
			for i = 1, #layer.objects do
--				print("path", tilesetimages[layer.objects[i].gid].path)
				tpt[#tpt+1] = tilesetimages[layer.objects[i].gid].path
			end
		end
	end
	local tp = TexturePack.new(tpt, nil, nil, { format=myformat, } )
	-- tileset images function
	local function parseImage(xobject, xlayer)
		local bitmap = Bitmap.new(tp:getTextureRegion(tilesetimages[xobject.gid].path))
		bitmap:setAnchorPoint(0, 1) -- because I always forget to modify Tiled objects alignment
		-- supports Tiled image scaling
		local scalex, scaley = xobject.width/bitmap:getWidth(), xobject.height/bitmap:getHeight()
		bitmap:setScale(scalex, scaley)
		bitmap:setRotation(xobject.rotation)
		bitmap:setPosition(xobject.x, xobject.y)
		xlayer:addChild(bitmap)
	end
	-- ____  _    _ _____ _      _____    _      ________      ________ _      
	--|  _ \| |  | |_   _| |    |  __ \  | |    |  ____\ \    / /  ____| |     
	--| |_) | |  | | | | | |    | |  | | | |    | |__   \ \  / /| |__  | |     
	--|  _ <| |  | | | | | |    | |  | | | |    |  __|   \ \/ / |  __| | |     
	--| |_) | |__| |_| |_| |____| |__| | | |____| |____   \  /  | |____| |____ 
	--|____/ \____/|_____|______|_____/  |______|______|   \/   |______|______|
	for i = 1, #tm.layers do
		local layer = tm.layers[i]
		local tilemaps = {}
		local group -- group = Sprite.new()
		-- _______ _____ _      ______ _           __     ________ _____  
		--|__   __|_   _| |    |  ____| |        /\\ \   / /  ____|  __ \ 
		--   | |    | | | |    | |__  | |       /  \\ \_/ /| |__  | |__) |
		--   | |    | | | |    |  __| | |      / /\ \\   / |  __| |  _  / 
		--   | |   _| |_| |____| |____| |____ / ____ \| |  | |____| | \ \ 
		--   |_|  |_____|______|______|______/_/    \_\_|  |______|_|  \_\
		-- this is the classic "Tileset" tile layers
		-- background = bg, foreground = fg
		if layer.type == "tilelayer" and (layer.name:match("bg") or layer.name:match("fg")) then
			if layer.name:match("bg") then group = xlayers["bg"]
			else group = xlayers["fg"]
			end
			for y = 1, layer.height do
				for x = 1, layer.width do
					local index = x + (y - 1) * layer.width
					local gid = layer.data[index]
					local gidtileset = gid2tileset(tm, gid)
					if gidtileset then
						local tilemap
						if tilemaps[gidtileset] then
							tilemap = tilemaps[gidtileset]
						else
							tilemap = TileMap.new(
								layer.width, layer.height,
								gidtileset.texture, gidtileset.tilewidth, gidtileset.tileheight,
								gidtileset.spacing, gidtileset.spacing,
								gidtileset.margin, gidtileset.margin,
								tm.tilewidth, tm.tileheight
							)
							tilemaps[gidtileset] = tilemap
							group:addChild(tilemap)
						end
						local tx = (gid - gidtileset.firstgid) % gidtileset.numcols + 1
						local ty = math.floor((gid - gidtileset.firstgid) / gidtileset.numcols) + 1
						tilemap:setTile(x, y, tx, ty)
					end
				end
			end
			group:setAlpha(layer.opacity)
		--  ____  ____       _ ______ _____ _______ _           __     ________ _____  
		-- / __ \|  _ \     | |  ____/ ____|__   __| |        /\\ \   / /  ____|  __ \ 
		--| |  | | |_) |    | | |__ | |       | |  | |       /  \\ \_/ /| |__  | |__) |
		--| |  | |  _ < _   | |  __|| |       | |  | |      / /\ \\   / |  __| |  _  / 
		--| |__| | |_) | |__| | |___| |____   | |  | |____ / ____ \| |  | |____| | \ \ 
		-- \____/|____/ \____/|______\_____|  |_|  |______/_/    \_\_|  |______|_|  \_\
		-- objects layers can be for decoration (images and shapes) and physics (Bump)
		elseif layer.type == "objectgroup" then
			local o
			local myshape, mytable
			local levelsetup = {}
			--     _                  _                           
			--    | |                | |                          
			--  __| | ___  ___ ___   | | __ _ _   _  ___ _ __ ___ 
			-- / _` |/ _ \/ __/ _ \  | |/ _` | | | |/ _ \ '__/ __|
			--| (_| |  __/ (_| (_) | | | (_| | |_| |  __/ |  \__ \
			-- \__,_|\___|\___\___/  |_|\__,_|\__, |\___|_|  |___/
			--                                 __/ |              
			--                                |___/               
			if layer.name:match("bg_deco_images") then
				for i = 1, #layer.objects do
					parseImage(layer.objects[i], xlayers["bg"])
				end
			elseif layer.name:match("fg_deco_images") then
				for i = 1, #layer.objects do
					parseImage(layer.objects[i], xlayers["fg"])
				end
			elseif layer.name:match("bg_deco_shapes") then
				for i = 1, #layer.objects do
					o = layer.objects[i]
					myshape, mytable = nil, nil
					local color = math.random(0xffffff)
					local shapelinecolor = 0xffffff
					if o.shape == "point" then
						shapelinecolor = math.random(0xffffff)
					end
					mytable = {
						shapelinewidth=1, shapelinecolor=shapelinecolor,
						color=color,
					}
					levelsetup = {}
					for k, v in pairs(mytable) do levelsetup[k] = v end
					myshape = self:buildShapes(o, levelsetup)
					myshape:setPosition(o.x, o.y)
					xlayers["bg"]:addChild(myshape)
				end
			elseif layer.name:match("fg_deco_shapes") then
				for i = 1, #layer.objects do
					o = layer.objects[i]
					myshape, mytable = nil, nil
					local color = math.random(0xffffff)
					local shapelinecolor = 0xffffff
					if o.shape == "point" then
						shapelinecolor = math.random(0xffffff)
					end
					mytable = {
						shapelinewidth=1, shapelinecolor=shapelinecolor,
						color=color,
					}
					levelsetup = {}
					for k, v in pairs(mytable) do levelsetup[k] = v end
					myshape = self:buildShapes(o, levelsetup)
					myshape:setPosition(o.x, o.y)
					xlayers["fg"]:addChild(myshape)
				end
			--       _               _            _                           
			--      | |             (_)          | |                          
			-- _ __ | |__  _   _ ___ _  ___ ___  | | __ _ _   _  ___ _ __ ___ 
			--| '_ \| '_ \| | | / __| |/ __/ __| | |/ _` | | | |/ _ \ '__/ __|
			--| |_) | | | | |_| \__ \ | (__\__ \ | | (_| | |_| |  __/ |  \__ \
			--| .__/|_| |_|\__, |___/_|\___|___/ |_|\__,_|\__, |\___|_|  |___/
			--| |           __/ |                          __/ |              
			--|_|          |___/                          |___/               
			-- add a physics body to the shapes (Bump)
			elseif layer.name:match("physics_grounds") then
				for i = 1, #layer.objects do
					o = layer.objects[i]
					o.isfloor = true -- Bump id
					-- physics body
					xbworld:add(o, o.x, o.y, o.width, o.height)
					-- decor (optional)
					if g_currlevel == 1 then
						local texpath = "gfx/textures/wdipagu_2K_Albedo.jpg_0007.png"
						mytable = {
							texpath=texpath, istexpot=true, scalex=1,
						}
						levelsetup = {}
						for k, v in pairs(mytable) do levelsetup[k] = v end
						myshape = self:buildShapes(o, levelsetup)
						myshape:setPosition(o.x, o.y)
						xlayers["bg"]:addChild(myshape)
					end
				end
			--            _                 
			--           | |                
			--  __ _  ___| |_ ___  _ __ ___ 
			-- / _` |/ __| __/ _ \| '__/ __|
			--| (_| | (__| || (_) | |  \__ \
			-- \__,_|\___|\__\___/|_|  |___/
			elseif layer.name == "physics_players" then -- player1
				for i = 1, #layer.objects do
					o = layer.objects[i]
					local opos = vector(o.x, o.y)
					-- EPlayer1:init(xspritelayer, xpos)
					self.player1 = EPlayer1.new(xlayers["actors"], opos)
					xtiny.tworld:addEntity(self.player1)
					-- physics body
					xbworld:add(
						self.player1,
						self.player1.pos.x, self.player1.pos.y,
						self.player1.collbox.w, self.player1.collbox.h
					)
				end
			end
			-- some cleaning?
			o = nil
			myshape, mytable = nil, nil
			levelsetup = {}
		end
	end
end

-- deco shapes
function TiledLevels:buildShapes(xobject, xlevelsetup)
	local myshape -- Tiled shapes: ellipse, point, polygon, polyline, rectangle, text
	local tablebase = {}
	if xobject.shape == "ellipse" then
		tablebase = {
			x=xobject.x, y=xobject.y,
			w=xobject.width, h=xobject.height,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Ellipse.new(tablebase)
	elseif xobject.shape == "point" then
		tablebase = {
			x=xobject.x, y=xobject.y,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Point.new(tablebase)
	elseif xobject.shape == "polygon" then
		tablebase = {
			x=xobject.x, y=xobject.y,
			coords=xobject.polygon,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Polygon.new(tablebase)
	elseif xobject.shape == "polyline" then -- lines
		tablebase = {
			x=xobject.x, y=xobject.y,
			coords=xobject.polyline,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Polyline.new(tablebase)
	elseif xobject.shape == "rectangle" then
		tablebase = {
			x=xobject.x, y=xobject.y,
			w=xobject.width, h=xobject.height,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Rectangle.new(tablebase)
	elseif xobject.shape == "text" then
		tablebase = {
			x=xobject.x, y=xobject.y,
			text=xobject.text,
			w=xobject.width, h=xobject.height,
			rotation=xobject.rotation,
		}
		for k, v in pairs(xlevelsetup) do tablebase[k] = v end
		myshape = Tiled_Shape_Text.new(tablebase)
	else
		print("*** CANNOT PROCESS THIS SHAPE! ***", xobject.shape, xobject.name)
		return
	end

	return myshape
end

TILED DECO SHAPES

Here are the Classes to build the Tiled decorative shapes (you may want to put each shape in separate files).

Tiled_Shape_Ellipse = Core.class(Sprite)

function Tiled_Shape_Ellipse:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or 0
	params.h = xparams.h or 0
	params.steps = xparams.steps or 32 -- 24
	params.shapelinewidth = xparams.shapelinewidth or nil
	params.shapelinecolor = xparams.shapelinecolor or nil
	params.shapelinealpha = xparams.shapelinealpha or 1
	params.color = xparams.color or nil
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.texpath = xparams.texpath or nil
	params.istexpot = xparams.istexpot or nil
	params.scalex = xparams.scalex or 1
	params.scaley = xparams.scaley or params.scalex
	params.skewx = xparams.skewx or 0 -- angle in degrees
	params.skewy = xparams.skewy or params.skewx -- angle in degrees
	params.rotation = xparams.rotation or 0
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = Shape.new()
	if params.shapelinewidth then
		img:setLineStyle(params.shapelinewidth, params.shapelinecolor, params.shapelinealpha)
	end
	if params.texpath then
		local tex
		if not params.istexpot then
			tex = Texture.new(params.texpath, false, { wrap = Texture.REPEAT, extend = false, } )
		else
			tex = Texture.new(params.texpath, false, { wrap = Texture.REPEAT, } )
		end
		local skewanglex = math.rad(params.skewx)
		local skewangley = math.rad(params.skewy)
		local matrix = Matrix.new(
			params.scalex, math.tan(skewanglex), math.tan(skewangley), params.scaley, 0, 0
		)
		img:setFillStyle(Shape.TEXTURE, tex, matrix)
		tex = nil
	elseif params.color then
		img:setFillStyle(Shape.SOLID, params.color, params.alpha)
	else
		img:setFillStyle(Shape.NONE)
	end
	img:beginPath()
	for i = 0, 360, 360 / params.steps  do
		img:lineTo(
			(params.w / 2) + params.w / 2 * math.cos(^<i),
			(params.h / 2) + params.h / 2 * math.sin(^<i)
		)
	end
	img:closePath()
	img:endPath()
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

Tiled_Shape_Point = Core.class(Sprite)

function Tiled_Shape_Point:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or 0
	params.h = xparams.h or 0
	params.shapelinewidth = xparams.shapelinewidth or 1
	params.shapelinecolor = xparams.shapelinecolor or nil
	params.shapelinealpha = xparams.shapelinealpha or 1
	params.color = xparams.color or nil -- hex
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.rotation = xparams.rotation or 0
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = Shape.new()
	img:setLineStyle(params.shapelinewidth, params.shapelinecolor, params.shapelinealpha)
	img:beginPath()
	img:moveTo(0,0)
	img:lineTo(1, 0)
	img:endPath()
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

Tiled_Shape_Polygon = Core.class(Sprite)

function Tiled_Shape_Polygon:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or 0
	params.h = xparams.h or 0
	params.coords = xparams.coords or nil
	params.shapelinewidth = xparams.shapelinewidth or nil
	params.shapelinecolor = xparams.shapelinecolor or nil
	params.shapelinealpha = xparams.shapelinealpha or 1
	params.color = xparams.color or nil -- hex
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.texpath = xparams.texpath or nil
	params.istexpot = xparams.istexpot or nil
	params.scalex = xparams.scalex or 1
	params.scaley = xparams.scaley or params.scalex
	params.skewx = xparams.skewx or 0 -- angle in degrees
	params.skewy = xparams.skewy or params.skewx -- angle in degrees
	params.rotation = xparams.rotation or 0
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = Shape.new()
	if params.shapelinewidth then
		img:setLineStyle(params.shapelinewidth, params.shapelinecolor, params.shapelinealpha)
	end
	if params.texpath then
		local tex
		if not params.istexpot then
			tex = Texture.new(params.texpath, false, { wrap = Texture.REPEAT, extend = false, } )
		else
			tex = Texture.new(params.texpath, false, { wrap = Texture.REPEAT, } )
		end
		local skewanglex = math.rad(params.skewx)
		local skewangley = math.rad(params.skewy)
		local matrix = Matrix.new(
			params.scalex, math.tan(skewanglex), math.tan(skewangley), params.scaley, 0, 0
		)
		img:setFillStyle(Shape.TEXTURE, tex, matrix)
		tex = nil
	elseif params.color then
		img:setFillStyle(Shape.SOLID, params.color, params.alpha)
	else
		img:setFillStyle(Shape.NONE)
	end
	img:beginPath()
	img:moveTo(params.coords[1].x, params.coords[1].y)
	for p = 2, #params.coords do
		img:lineTo(params.coords[p].x, params.coords[p].y)
	end
	img:closePath()
	img:endPath()
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

Tiled_Shape_Polyline = Core.class(Sprite)

function Tiled_Shape_Polyline:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or 0
	params.h = xparams.h or 0
	params.coords = xparams.coords or nil
	params.shapelinewidth = xparams.shapelinewidth or 1
	params.shapelinecolor = xparams.shapelinecolor or nil
	params.shapelinealpha = xparams.shapelinealpha or 1
	params.color = xparams.color or nil -- hex
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.rotation = xparams.rotation or 0
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = Shape.new()
	img:setLineStyle(params.shapelinewidth, params.shapelinecolor, params.shapelinealpha)
	img:setFillStyle(Shape.NONE)
	img:beginPath()
	img:moveTo(params.coords[1].x, params.coords[1].y)
	for p = 2, #params.coords do
		img:lineTo(params.coords[p].x, params.coords[p].y)
	end
--	img:closePath()
	img:endPath()
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

Tiled_Shape_Rectangle = Core.class(Sprite)

function Tiled_Shape_Rectangle:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or nil
	params.h = xparams.h or nil
	params.shapelinewidth = xparams.shapelinewidth or 0
	params.shapelinecolor = xparams.shapelinecolor or nil
	params.shapelinealpha = xparams.shapelinealpha or 1
	params.color = xparams.color or nil -- hex
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.texpath = xparams.texpath or nil
	params.istexpot = xparams.istexpot or nil
	params.scalex = xparams.scalex or 1
	params.scaley = xparams.scaley or params.scalex
	params.skewx = xparams.skewx or 0 -- angle in degrees
	params.skewy = xparams.skewy or params.skewx -- angle in degrees
	params.rotation = xparams.rotation or nil
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = Shape.new()
	img:setLineStyle(params.shapelinewidth, params.shapelinecolor, params.shapelinealpha)
	if params.texpath then
		local tex
		if not params.istexpot then
			tex = Texture.new(params.texpath, false, { wrap = Texture.REPEAT, extend = false, } )
		else
			tex = Texture.new(params.texpath, false, { wrap=Texture.REPEAT, } )
		end
		local skewanglex = math.rad(params.skewx)
		local skewangley = math.rad(params.skewy)
		local matrix = Matrix.new(
			params.scalex, math.tan(skewanglex), math.tan(skewangley), params.scaley, 0, 0
		)
		img:setFillStyle(Shape.TEXTURE, tex, matrix)
		tex = nil
	elseif params.color then
		img:setFillStyle(Shape.SOLID, params.color, params.alpha)
	else
		img:setFillStyle(Shape.NONE)
	end
	img:beginPath()
	img:moveTo(0, 0)
	img:lineTo(params.w, 0)
	img:lineTo(params.w, params.h)
	img:lineTo(0, params.h)
	img:lineTo(0, 0)
	img:endPath()
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

Tiled_Shape_Text = Core.class(Sprite)

function Tiled_Shape_Text:init(xparams)
	-- params
	local params = xparams or {}
	params.x = xparams.x or nil
	params.y = xparams.y or nil
	params.w = xparams.w or nil
	params.h = xparams.h or nil
	params.text = xparams.text or nil
	params.ttf = xparams.ttf or nil
	params.color = xparams.color or nil
	params.r = xparams.r or 1
	params.g = xparams.g or 1
	params.b = xparams.b or 1
	params.alpha = xparams.alpha or 1
	params.scalex = xparams.scalex or 1
	params.scaley = xparams.scaley or params.scalex
	params.rotation = xparams.rotation or nil
	params.data = xparams.data or nil
	params.value = xparams.value or nil
	-- image
	local img = TextField.new(params.ttf, params.text, params.text)
--	img:setAnchorPoint(0, -1)
	if params.color then
		img:setTextColor(color)
	end
	img:setRotation(params.rotation)
	img:setAlpha(params.alpha)
	img:setColorTransform(params.r, params.g, params.b, params.alpha)
	-- auto scale
	local currw = img:getWidth()
	img:setScale(params.w/currw)
	--
--	self.w, self.h = img:getWidth(), img:getHeight()
	self:addChild(img)
end

DEMO PROJECT

Media:Tiled demo bump.zip (tip: right click -> Save Link As)


Tiled