In order to use physics to drive our game interactions, we'll need some physics content for our game world to give characters some floors (and walls) to interact with.
We'll create a long physics block for every unbroken row of block tiles.
In categories.lua
, add a new entry to the table being returned:
return { ground = { groupIndex = ID.general; categoryBits = ID.wall, maskBits = ID.sprite; }, }
Save this file, open world.lua
, and load this module at the top of the file.
local categories = require "categories" local function matchPointPlacement(target, referenceX, referenceY, frame, targetX, targetY) Since the module is working with collisions, it will also need physics. Local physics = require "physics" local categories = require "categories"
Open the file world.lua
and locate the self:Load(map)
function. After looping over the map, make sure that in case the world object is being reused, any previous platform objects are cleared:
end if self.Blocks then for _, block in ipairs(self.Blocks) do display.remove(block) end end self.Map = map
Then, make sure that the world starts with its list of solids being newly empty:
display.remove(block)
end
end
self.Blocks = {}
self.Map = map
Look over each row of the map at a time:
self.Blocks = {} for h, row in ipairs(map) do end self.Map = map
Then, for each row, gather the position, ground style, and width of each run of blocks using a custom iterator (which we'll write next):
for h, row in ipairs(map) do for start, kind, width in scanRow(row) do end end
Before using these dimensions to create the blocks, we'll back out for a moment to create the iterator that will treat the map row as a sequence of blocks. Move back up the file before the module function and frame in the form of an iterator that works with numeric indices:
until dY == -1 end local function advance(row, start) end local function scanRow(row) return advance, row, 0 end return function (terrain, columns, rows)
When the generator comes back to a row at the start or middle of a run of ground blocks, it scans to the end of that run before proceeding:
local function advance(row, start) while row[start] and row[start].isGround do start = start + 1 end end
It then advances until it finds a block that contains solid ground:
start = start + 1 end repeat start = start + 1 until row[start].isGround end
If it reaches the end of the row first, scanning is complete and it ends the loop by returning nil:
repeat start = start + 1 if not row[start] then return end until row[start].isGround
Once it has the beginning of a block run, it scans forward on a new counter until it finds the end of that run or the row:
until row[start].isGround local stop = start + 1 while row[stop] and row[stop].isGround do stop = stop + 1 end end
Finally, it returns the start position as well as the function used to create the blocks in the right size and style, along with the width, obtained by subtracting the beginning from the end:
stop = stop + 1
end
return start, row[start].isGround, stop - start
end
We here take advantage of a feature of Lua, where any non-nil value is considered true. So we can store functions with ground spaces that create the right sort of ground, and nil on those spaces that don't count as ground.
Back inside the loop, it's time to take the information from the iterator and make blocks with it. Multiply the index of the current row as well as the start and width of the block by the world's tile dimensions to determine the dimensions for the new floor:
for start, kind, width in scanRow(row) do
local block = kind(self, (start - 1) * self.HSize, (h - 1) * self.VSize, width * self.HSize, self.VSize)
And finally we store the block in the list we created earlier:
physics.addBody(block, 'static', {filter = categories.ground})
table.insert(self.Blocks, block)
end
We picked out individual streaks of consecutive blocks in each row of the tile map, and gave each one a physics identity, allowing it to block the passage of solid characters. We gave these blocks a generic grouping so that they will collide with nearly all other objects.
There are two reasons to consolidate adjacent blocks rather than give each block tile its very own physics square:
Also, the iterator we created to scan for blocks is a bit inefficient, but fixing it (by returning the ends of blocks instead of their beginnings) makes the code's usage harder to understand and isn't worth it unless it has a significant impact on load times.
18.191.178.211