SNKRX/engine/map/tilemap.lua

67 lines
3.1 KiB
Lua

-- A tilemap class responsible for the loading and drawing of maps made of tiles.
-- The x, y coordinates passed in represent the center of the map.
-- A tileset object containing the tileset to be used by the map must be passed in, as well as a grid object containing the map itself.
-- If tile_rules is also passed in, then the grid instance must contain its values in relation to what the tiling rules expect.
-- If no tiling rules are present then the grid will contain the 1D index of each tile in the tileset, so if the tileset has 5 columns, the first element in the second row will be numbered 6 in the grid.
-- If solid_rules is passed in, then the that function should receive a tile index and return true on those that are supposed to form a solid object, for instance:
-- function(index) return index ~= 0 end would make every tile index that isn't 0 into a solid object.
-- The created solids are stored in .solids after the tilemap instance is created. They should be added to the same group that you want gameplay objects to collide with the map's solid walls.
-- Solids are evaluated before tile rules are applied to the tile grid.
Tilemap = Object:extend()
function Tilemap:init(x, y, tileset, tile_grid, tile_rules, solid_rules)
self.tileset = tileset
self.grid = tile_grid
self.x, self.y = x, y
self.w, self.h = self.grid.w*self.tileset.tile_w, self.grid.h*self.tileset.tile_h
self.tile_rules = tile_rules
self.solid_rules = solid_rules
-- Create solids from the tile grid
local tw, th = self.tileset.tile_w, self.tileset.tile_h
if self.solid_rules then
local ox, oy = self.x - self.w/2, self.y - self.h/2
local tile_polygons = {}
for i = 1, self.grid.w do
for j = 1, self.grid.h do
if self.solid_rules(self.grid:get(i, j)) then
table.insert(tile_polygons, Polygon({ox + (i-1)*tw, oy + (j-1)*th, ox + i*tw, oy + (j-1)*th, ox + i*tw, oy + j*th, ox + (i-1)*tw, oy + j*th}))
end
end
end
self.solids_vertices = {}
for _, solid in ipairs(Polygon.merge_polygons(tile_polygons)) do
table.insert(self.solids_vertices, solid)
end
end
if self.tile_rules:is(TilekitRules) then
self.grid = Grid(self.grid.w, self.grid.h, self.tile_rules.process({w = self.grid.w, h = self.grid.h, data = self.grid.grid}).data)
end
-- Create spritebatch
self.spritebatch = love.graphics.newSpriteBatch(self.tileset.image.image, 8192, 'static')
for i = 1, self.grid.w do
for j = 1, self.grid.h do
local v = self.grid:get(i, j)
if v ~= 0 then
self.spritebatch:add(self.tileset:get_quad(v), (i-1)*tw, (j-1)*th)
end
end
end
end
function Tilemap:draw(r, sx, sy, ox, oy)
love.graphics.draw(self.spritebatch, self.x - self.w/2, self.y - self.h/2, r or 0, sx or 1, sy or sx or 1, ox or 0, oy or 0)
end
-- This class is responsible for loading tile rules exported by rxi's Tilekit https://rxi.itch.io/tilekit
-- An instance of this class should be passed in as the third argument for a Tilemap instance
TilekitRules = Object:extend()
function TilekitRules:init(rules_filename)
self.process = require('assets/maps/' .. rules_filename)
end