Difference between revisions of "Tiled Bump"
(wip) |
|||
Line 2: | Line 2: | ||
== Description == | == Description == | ||
− | Here we will set up Gideros to work with Tiled | + | Here we will set up Gideros to work with Tiled with Bump for collision detection. |
− | Tiled | + | 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, | + | 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) | ||
− | -- | + | -- 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() | ||
− | -- | + | -- cbump (bworld) |
− | local bworld = | + | local bump = require "cbump" |
− | -- | + | 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 | ||
− | -- | + | -- _ ________ ________ _ _____ |
+ | --| | | ____\ \ / / ____| | / ____| | ||
+ | --| | | |__ \ \ / /| |__ | | | (___ | ||
+ | --| | | __| \ \/ / | __| | | \___ \ | ||
+ | --| |____| |____ \ / | |____| |____ ____) | | ||
+ | --|______|______| \/ |______|______|_____/ | ||
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 | + | -- global variables |
g_currlevel = 1 -- 1 = Collection of Images, 2 = Tileset | g_currlevel = 1 -- 1 = Collection of Images, 2 = Tileset | ||
− | g_keyleft = KeyCode.LEFT | + | g_keyleft = KeyCode.LEFT |
− | g_keyright = KeyCode.RIGHT | + | g_keyright = KeyCode.RIGHT |
− | g_keyup = KeyCode.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 | + | * '''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 | ||
− | + | 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 | ||
− | |||
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 | + | -- 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 |
− | -- | + | -- 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 | + | -- 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 | + | local shapelinecolor = 0xffffff |
+ | if o.shape == "point" then | ||
+ | shapelinecolor = math.random(0xffffff) | ||
+ | end | ||
mytable = { | mytable = { | ||
− | shapelinewidth=1, shapelinecolor= | + | shapelinewidth=1, shapelinecolor=shapelinecolor, |
− | |||
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 | + | local shapelinecolor = 0xffffff |
+ | if o.shape == "point" then | ||
+ | shapelinecolor = math.random(0xffffff) | ||
+ | end | ||
mytable = { | mytable = { | ||
− | shapelinewidth= | + | shapelinewidth=1, shapelinecolor=shapelinecolor, |
− | |||
color=color, | color=color, | ||
} | } | ||
Line 321: | Line 345: | ||
--| | __/ | __/ | | --| | __/ | __/ | | ||
--|_| |___/ |___/ | --|_| |___/ |___/ | ||
− | -- add a physics body to the shapes ( | + | -- add a physics body to the shapes (Bump) |
− | elseif layer.name | + | 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 |
− | -- | + | -- 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" | |
− | |||
− | -- | ||
− | if g_currlevel == 1 then | ||
− | local | ||
mytable = { | mytable = { | ||
− | texpath= | + | texpath=texpath, istexpot=true, scalex=1, |
− | |||
− | |||
} | } | ||
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.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 | 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 | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== DEMO PROJECT == | == DEMO PROJECT == | ||
− | '''[[Media:Tiled demo | + | '''[[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.
level1 using Collection of Images
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:
- we need to link the Tiled Tileset images to their correct tile id
- optionally it is best (performance wise) to pack the images
- 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)