improvement: refactor the map system

This commit is contained in:
Kazhnuz 2021-03-23 13:32:48 +01:00
parent a5f362ceaa
commit b691d96c99
12 changed files with 352 additions and 275 deletions

View file

@ -1,7 +1,7 @@
local cwd = (...):gsub('%.init$', '') .. "."
local mapObjects = {}
mapObjects.Sti = require(cwd .. "sti")
mapObjects.Sti = require(cwd .. "tiled")
mapObjects.Base = require(cwd .. "parent")
return mapObjects

View file

@ -1,271 +0,0 @@
local cwd = (...):gsub('%.sti$', '') .. "."
local Parent = require(cwd .. "parent")
local STI = require(cwd .. "libs.sti")
local StiMap = Parent:extend()
function StiMap:new(world, mapfile)
self.sti = STI(mapfile)
StiMap.super.new(self, world)
self:setBackgroundColorFromTable(self.sti.backgroundcolor)
self.mapname = self:getMapName(mapfile)
self.objectlayer = 0
end
function StiMap:loadObjects()
self:loadCollisions()
self:loadPlayers()
self:loadActors()
self.objectlayer = self:getObjectLayer()
end
function StiMap:getObjectLayer()
local objectlayer = 0
for i, layer in ipairs(self.sti.layers) do
if (layer.name == "objects") then
objectlayer = i
end
self.nbrLayer = i
end
return objectlayer
end
function StiMap:getMapName(mapfile)
local filepath = utils.string.split(mapfile, "/")
local filenameMap = utils.string.split(filepath[#filepath], ".")
return filepath[#filepath - 1] .. "." .. filenameMap[1]
end
function StiMap:getDimensions()
return self.sti.width * self.sti.tilewidth,
self.sti.height * self.sti.tileheight
end
-- UPDATE FUNCTION
-- Update or modify the map
function StiMap:resize(w, h)
self.sti:resize(w, h)
end
function StiMap:update(dt)
self.sti:update(dt)
end
-- LOADING FUNCTION
-- Load actors directly into the world
function StiMap:loadCollisions()
for k, objectlayer in pairs(self.sti.layers) do
if self.world:isCollisionIndexed(objectlayer.name) then
local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " collision layer"
core.debug:print("map/sti", debugstring)
for k, object in pairs(objectlayer.objects) do
self:newCollision(objectlayer, object)
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiMap:loadActors()
for k, objectlayer in pairs(self.sti.layers) do
if self.world:isActorIndexed(objectlayer.name) then
local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " actor layer"
core.debug:print("map/sti", debugstring)
for k, object in pairs(objectlayer.objects) do
if (object.properties.batchActor) then
self:batchActor(objectlayer, object)
else
self:newActor(objectlayer, object)
end
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiMap:loadPlayers()
for k, objectlayer in pairs(self.sti.layers) do
if (objectlayer.name == "player") then
local debugstring = "loading at most " .. #objectlayer.objects .. " actors in " .. objectlayer.name .. " actor layer"
core.debug:print("map/sti", debugstring)
local i = 1
for k, object in pairs(objectlayer.objects) do
self:newPlayer(object, i)
i = i + 1
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiMap:batchActor(objectlayer, object)
local name = objectlayer.name
local gwidth = object.properties.gwidth or self.sti.tilewidth
local gheight = object.properties.gheight or self.sti.tileheight
local x = object.x
local y = object.y
local z = object.properties.z or 0
local w = object.width
local h = object.height
local cellHor = math.ceil(w / gwidth)
local cellVert = math.ceil(h / gheight)
for i=1, cellHor do
for j=1, cellVert do
self.world:newActor(name, x + (i-1)*gwidth, y + (j-1)*gheight, z, object.properties)
end
end
end
function StiMap:newActor(objectlayer, object)
local z = object.properties.z or 0
local adaptPosition = object.properties.adaptPosition or false
local y = object.y
if (adaptPosition) then
y = y + z
end
self.world:newActor(objectlayer.name, object.x, y, z, object.properties, self.mapname)
end
function StiMap:newCollision(objectlayer, object)
local z = object.properties.z or 0
local d = object.properties.d or 16
local fromTop = object.properties.fromTop or false
local y = object.y
if (fromTop) then
local poschange = z .. ";" .. y .. " => " .. z-d .. ";" .. y+z
core.debug:print("map/sti", "create from top, set z and y: " .. poschange)
y = y + z
z = z - d
end
self.world:newCollision(objectlayer.name, object.x, y, z, object.width, object.height, d)
end
function StiMap:haveTileTypeInRect(x, y, w, h, type)
local x1, y1, x2, y2 = self:getTileRectangle(x, y, x + w, y + h)
local isSolid = false
for i = x1, x2, 1 do
for j = y1, y2, 1 do
if (self:getTileTypeAtCoord(i, j) == type) then
isSolid = true
end
end
end
return isSolid
end
function StiMap:getTileRectangle(x, y, x2, y2)
local xx, yy = self:convertPixelToTile (x, y)
local xx2, yy2 = self:convertPixelToTile (x2, y2)
return xx, yy, xx2, yy2
end
function StiMap:getTileTypeAtPoint(x, y)
local xx, yy = self:convertPixelToTile (x, y)
return self:getTileTypeAtCoord(xx, yy)
end
function StiMap:getTileTypeAtCoord(x, y)
local canSearch = true
local currentType = nil
for _, layer in ipairs(self.sti.layers) do
if (canSearch) then
if (layer.type == "tilelayer") then
local tileset, tileid = self:getTileId(layer.name, x, y)
local type = self:getTileType(tileset, tileid)
if (type ~= nil) then
currentType = type
end
else
if (layer.name=="objects") then
canSearch = false
end
end
end
end
return currentType
end
function StiMap:convertPixelToTile(x, y)
local xx, yy = self.sti:convertPixelToTile (x, y)
return math.ceil(xx), math.ceil(yy)
end
function StiMap:getTileType(tileset, id)
local tilesetData = self.sti.tilesets[tileset]
if ((tileset == -1) or (id == -1)) then
return nil
end
if (tilesetData ~= nil) then
for i, tile in ipairs(tilesetData.tiles) do
if (tile.id == id) and (tile.type ~= nil) then
return tile.type
end
end
end
return "non-solid"
end
function StiMap:getTileId(layer, x, y)
local line = self.sti.layers[layer].data[y]
if (line ~= nil) then
local tile = line[x]
if not tile then
return -1, -1
end
return tile.tileset, tile.id
end
return -1, -1
end
function StiMap:newPlayer(object, i)
local z = object.properties.z or 0
local adaptPosition = object.properties.adaptPosition or false
local y = object.y
if (adaptPosition) then
core.debug:print("map/sti", "adapting position, set y: " .. y .. " => ", y+z)
y = y + z
end
self.world:addPlayer(object.x, y, z, i)
end
-- DRAW FUNCTIONS
-- Draw the map
function StiMap:drawUpperLayers()
if (self.objectlayer > 0) then
for i = self.objectlayer, self.nbrLayer, 1 do
self:drawLayer(i)
end
end
end
function StiMap:drawLowerLayers()
for i = 1, self.objectlayer, 1 do
self:drawLayer(i)
end
end
function StiMap:drawLayer(id)
local layer = self.sti.layers[id]
if (layer ~= nil) then
if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then
print("upper " .. id)
self.sti:drawLayer(layer)
end
end
end
return StiMap

View file

@ -0,0 +1,61 @@
local Parent = require "core.modules.world.maps.parent"
local TiledMap = Parent:extend()
local StiWrapper = require "core.modules.world.maps.tiled.stiwrapper"
local TiledMixins = require "core.modules.world.maps.tiled.mixins"
TiledMap:implement(TiledMixins)
function TiledMap:new(world, mapfile)
self.wrapper = StiWrapper(self, mapfile, 0, 0)
TiledMap.super.new(self, world)
self:setBackgroundColorFromTable(self.wrapper.sti.backgroundcolor)
self.mapname = self:getMapName(mapfile)
end
function TiledMap:getMapName(mapfile)
local filepath = utils.string.split(mapfile, "/")
local filenameMap = utils.string.split(filepath[#filepath], ".")
return filepath[#filepath - 1] .. "." .. filenameMap[1]
end
function TiledMap:getDimensions()
return self.wrapper:getDimensions()
end
function TiledMap:loadObjects()
self.wrapper:loadObjects()
end
-- TILE FUNCTIONS
-- Get tiles
function TiledMap:haveTileTypeInRect(x, y, w, h, type)
return self.wrapper:haveTileTypeInRect(x, y, w, h, type)
end
-- UPDATE FUNCTION
-- Update or modify the map
function TiledMap:resize(w, h)
self.wrapper:resize(w, h)
end
function TiledMap:update(dt)
self.wrapper:update(dt)
end
-- DRAW FUNCTIONS
-- Handle drawing the wrapper
function TiledMap:drawUpperLayers()
self.wrapper:drawUpperLayers()
end
function TiledMap:drawLowerLayers()
self.wrapper:drawLowerLayers()
end
return TiledMap

View file

@ -745,10 +745,13 @@ end
--- Draw an individual Layer
-- @param layer The Layer to draw
function Map.drawLayer(_, layer)
function Map.drawLayer(_, layer, x, y)
local r,g,b,a = lg.getColor()
lg.setColor(r, g, b, a * layer.opacity)
print(x, y)
lg.translate(x, y)
layer:draw()
lg.translate(-x, -y)
lg.setColor(r,g,b,a)
end

View file

@ -0,0 +1,81 @@
local TiledMixins = Object:extend()
-- ACTOR ADDING FUNCTIONS
-- Add actor related to the map
function TiledMixins:batchActor(objectlayer, object, layerx, layery)
local name = objectlayer.name
local gwidth = object.properties.gwidth or self.sti.tilewidth
local gheight = object.properties.gheight or self.sti.tileheight
local x = object.x + layerx
local y = object.y + layery
local z = object.properties.z or 0
local w = object.width
local h = object.height
local cellHor = math.ceil(w / gwidth)
local cellVert = math.ceil(h / gheight)
for i = 1, cellHor do
for j = 1, cellVert do
self.world:newActor(name, x + (i - 1) * gwidth, y + (j - 1) * gheight, z, object.properties)
end
end
end
function TiledMixins:newActor(objectlayer, object, layerx, layery)
local z = object.properties.z or 0
local adaptPosition = object.properties.adaptPosition or false
local x = object.x + layerx
local y = object.y + layery
if (adaptPosition) then
y = y + z
end
self.world:newActor(objectlayer.name, x, y, z, object.properties, self.mapname)
end
function TiledMixins:newCollision(objectlayer, object, layerx, layery)
local z = object.properties.z or 0
local d = object.properties.d or 16
local fromTop = object.properties.fromTop or false
local x = object.x + layerx
local y = object.y + layery
if (fromTop) then
local poschange = z .. ";" .. y .. " => " .. z - d .. ";" .. y + z
core.debug:print("map/sti", "create from top, set z and y: " .. poschange)
y = y + z
z = z - d
end
self.world:newCollision(objectlayer.name, x, y, z, object.width, object.height, d)
end
function TiledMixins:newPlayer(object, i, layerx, layery)
local z = object.properties.z or 0
local adaptPosition = object.properties.adaptPosition or false
local x = object.x + layerx
local y = object.y + layery
if (adaptPosition) then
core.debug:print("map/sti", "adapting position, set y: " .. y .. " => ", y + z)
y = y + z
end
self.world:addPlayer(x, y, z, i)
end
-- INDEXATION FUNCTIONS
-- Verify if something is indexed
function TiledMixins:isCollisionIndexed(name)
return self.world:isCollisionIndexed(name)
end
function TiledMixins:isActorIndexed(name)
return self.world:isActorIndexed(name)
end
return TiledMixins

View file

@ -0,0 +1,204 @@
local StiWrapper = Object:extend()
local STI = require "core.modules.world.maps.tiled.libs.sti"
function StiWrapper:new(owner, mapfile, x, y)
self.sti = STI(mapfile)
self.owner = owner
self.x = x or 0
self.y = y or 0
self.objectlayer = 0
end
function StiWrapper:getDimensions()
return self.sti.width * self.sti.tilewidth, self.sti.height * self.sti.tileheight
end
-- UPDATE FUNCTION
-- Update or modify the map
function StiWrapper:resize(w, h)
self.sti:resize(w, h)
end
function StiWrapper:update(dt)
self.sti:update(dt)
end
-- OBJECT FUNCTIONS
-- Handle objets
function StiWrapper:loadObjects()
self:loadCollisions()
self:loadPlayers()
self:loadActors()
self.objectlayer = self:getObjectLayer()
end
function StiWrapper:loadCollisions()
for _, objectlayer in pairs(self.sti.layers) do
if self.owner:isCollisionIndexed(objectlayer.name) then
local debugstring =
"loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " collision layer"
core.debug:print("map/sti", debugstring)
for _, object in pairs(objectlayer.objects) do
self.owner:newCollision(objectlayer, object, self.x, self.y)
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiWrapper:loadActors()
for k, objectlayer in pairs(self.sti.layers) do
if self.owner:isActorIndexed(objectlayer.name) then
local debugstring =
"loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " actor layer"
core.debug:print("map/sti", debugstring)
for k, object in pairs(objectlayer.objects) do
if (object.properties.batchActor) then
self.owner:batchActor(objectlayer, object, self.x, self.y)
else
self.owner:newActor(objectlayer, object, self.x, self.y)
end
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiWrapper:loadPlayers()
for k, objectlayer in pairs(self.sti.layers) do
if (objectlayer.name == "player") then
local debugstring =
"loading at most " .. #objectlayer.objects .. " actors in " .. objectlayer.name .. " actor layer"
core.debug:print("map/sti", debugstring)
local i = 1
for k, object in pairs(objectlayer.objects) do
self.owner:newPlayer(object, i, self.x, self.y)
i = i + 1
end
self.sti:removeLayer(objectlayer.name)
end
end
end
function StiWrapper:getObjectLayer()
local objectlayer = 0
for i, layer in ipairs(self.sti.layers) do
if (layer.name == "objects") then
objectlayer = i
end
self.nbrLayer = i
end
return objectlayer
end
-- TILE FUNCTIONS
-- Handle tiles
function StiWrapper:haveTileTypeInRect(x, y, w, h, type)
local x1, y1, x2, y2 = self:getTileRectangle(x, y, x + w, y + h)
local isSolid = false
for i = x1, x2, 1 do
for j = y1, y2, 1 do
if (self:getTileTypeAtCoord(i, j) == type) then
isSolid = true
end
end
end
return isSolid
end
function StiWrapper:getTileRectangle(x, y, x2, y2)
local xx, yy = self:convertPixelToTile(x, y)
local xx2, yy2 = self:convertPixelToTile(x2, y2)
return xx, yy, xx2, yy2
end
function StiWrapper:getTileTypeAtPoint(x, y)
local xx, yy = self:convertPixelToTile(x, y)
return self:getTileTypeAtCoord(xx, yy)
end
function StiWrapper:getTileTypeAtCoord(x, y)
local canSearch = true
local currentType = nil
for _, layer in ipairs(self.sti.layers) do
if (canSearch) then
if (layer.type == "tilelayer") then
local tileset, tileid = self:getTileId(layer.name, x, y)
local type = self:getTileType(tileset, tileid)
if (type ~= nil) then
currentType = type
end
else
if (layer.name == "objects") then
canSearch = false
end
end
end
end
return currentType
end
function StiWrapper:convertPixelToTile(x, y)
local xx, yy = self.sti:convertPixelToTile(x - self.x, y - self.y)
return math.ceil(xx), math.ceil(yy)
end
function StiWrapper:getTileType(tileset, id)
local tilesetData = self.sti.tilesets[tileset]
if ((tileset == -1) or (id == -1)) then
return nil
end
if (tilesetData ~= nil) then
for i, tile in ipairs(tilesetData.tiles) do
if (tile.id == id) and (tile.type ~= nil) then
return tile.type
end
end
end
return "non-solid"
end
function StiWrapper:getTileId(layer, x, y)
local line = self.sti.layers[layer].data[y]
if (line ~= nil) then
local tile = line[x]
if not tile then
return -1, -1
end
return tile.tileset, tile.id
end
return -1, -1
end
-- DRAW FUNCTIONS
-- Draw the map
function StiWrapper:drawUpperLayers()
if (self.objectlayer > 0) then
for i = self.objectlayer, self.nbrLayer, 1 do
self:drawLayer(i)
end
end
end
function StiWrapper:drawLowerLayers()
for i = 1, self.objectlayer, 1 do
self:drawLayer(i)
end
end
function StiWrapper:drawLayer(id)
local layer = self.sti.layers[id]
if (layer ~= nil) then
if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then
self.sti:drawLayer(layer, self.x, self.y)
end
end
end
return StiWrapper

View file

@ -27,7 +27,6 @@ local BaseWorld = require(cwd .. "baseworld")
local World2D = BaseWorld:extend()
local Bump = require(cwd .. "libs.bump")
local CameraSystem = require(cwd .. "camera")
function World2D:new(scene, actorlist, mapfile, maptype)
World2D.super.new(self, scene, actorlist, mapfile, maptype)

View file

@ -30,7 +30,7 @@ end
function MenuScreenParent:drawForeground()
self.scene.assets.fonts["SA2font"]:print(self.title, 160, 12)
love.graphics.rectangle("line", const.X, const.Y, const.WIDTH, const.HEIGHT)
--love.graphics.rectangle("line", const.X, const.Y, const.WIDTH, const.HEIGHT)
self:draw()
end