Refactor level loading into a separate module for easy extraction
This commit is contained in:
parent
f7e2971ccd
commit
e0bc23f95c
214
level.lua
214
level.lua
@ -1,27 +1,24 @@
|
||||
local api = require("level_api")
|
||||
local level = {
|
||||
width = 0,
|
||||
height = 0,
|
||||
api = api,
|
||||
player_x = 0,
|
||||
player_y = 0,
|
||||
tile_width = 16,
|
||||
tile_height = 16,
|
||||
tiles = {},
|
||||
quads = {},
|
||||
tilesets = {},
|
||||
connections = {
|
||||
},
|
||||
}
|
||||
|
||||
level.autotile = require("autotile")
|
||||
|
||||
function level.init(self, filename, enemies)
|
||||
enemies:clear()
|
||||
tiles = {}
|
||||
connections = {}
|
||||
api:register_pre_load(function(self, image, data)
|
||||
self.tile_width = 16
|
||||
self.tile_height = 16
|
||||
self.tiles = {}
|
||||
self.tilesets = {}
|
||||
self.connectionOffsets = {}
|
||||
self.connections = {}
|
||||
self.autotile = require("autotile")
|
||||
|
||||
self.levelData = require("levels/" .. filename)
|
||||
self.width, self.height = image:getDimensions()
|
||||
self.levelData = data
|
||||
|
||||
for i,f in ipairs(self.levelData.walls) do
|
||||
for i,f in ipairs(data.walls) do
|
||||
local tex = love.graphics.newImage("tiles/"..f[1])
|
||||
self.tilesets[i] = {
|
||||
quad = love.graphics.newQuad(0, 0, self.tile_width, self.tile_height, tex),
|
||||
@ -32,7 +29,7 @@ function level.init(self, filename, enemies)
|
||||
args = f[3] or {},
|
||||
}
|
||||
end
|
||||
for i,f in ipairs(self.levelData.floors) do
|
||||
for i,f in ipairs(data.floors) do
|
||||
local tex = love.graphics.newImage("tiles/"..f[1])
|
||||
self.tilesets[i + 5] = {
|
||||
quad = love.graphics.newQuad(0, 0, self.tile_width, self.tile_height, tex),
|
||||
@ -43,8 +40,8 @@ function level.init(self, filename, enemies)
|
||||
args = f[3] or {},
|
||||
}
|
||||
end
|
||||
if self.levelData.doors then
|
||||
for i,f in ipairs(self.levelData.doors) do
|
||||
if data.doors then
|
||||
for i,f in ipairs(data.doors) do
|
||||
local tex = love.graphics.newImage("tiles/"..f[1])
|
||||
self.tilesets[i + 9] = {
|
||||
quad = love.graphics.newQuad(0, 0, self.tile_width, self.tile_height, tex),
|
||||
@ -56,100 +53,119 @@ function level.init(self, filename, enemies)
|
||||
}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local tileData = love.image.newImageData("levels/" .. self.levelData.map)
|
||||
local connectionOffsets = {}
|
||||
-- Walls and floors
|
||||
api:register_color({1, 1, 1}, function(self, x, y, value, data)
|
||||
local tileIndex = (y - 1) * self.width + x
|
||||
|
||||
self.width, self.height = tileData:getDimensions()
|
||||
for i=1,self.height do
|
||||
for j=1,self.width do
|
||||
local tileIndex = (i - 1) * self.width + j
|
||||
local index = math.ceil(value * 8)
|
||||
if index >= 5 then
|
||||
self.tiles[tileIndex] = (9 - index) + 14
|
||||
else
|
||||
self.tiles[tileIndex] = index + 10
|
||||
end
|
||||
end)
|
||||
|
||||
local r, g, b = tileData:getPixel(j - 1, i - 1)
|
||||
if r == g and r == b then
|
||||
local index = math.ceil(r * 8)
|
||||
if index >= 5 then
|
||||
self.tiles[tileIndex] = (9 - index) + 14
|
||||
else
|
||||
self.tiles[tileIndex] = index + 10
|
||||
end
|
||||
else
|
||||
self.tiles[tileIndex] = 0
|
||||
if g == 0 and b == 0 and r > 0 then
|
||||
local index = 9 - math.ceil(r * 8)
|
||||
-- Enemies
|
||||
api:register_color({1, 0, 0}, function(self, x, y, value, data)
|
||||
local tileIndex = (y - 1) * self.width + x
|
||||
local index = 9 - math.ceil(value * 8)
|
||||
|
||||
if self.levelData.enemies[index] then
|
||||
local enemy = self.levelData.enemies[index].data.new((j - 1) * self.tile_width, (i - 1) * self.tile_height)
|
||||
if self.levelData.enemies[index].props then
|
||||
for k,v in pairs(self.levelData.enemies[index].props) do
|
||||
print(k.." = "..v)
|
||||
enemy[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
enemies:add(enemy)
|
||||
|
||||
if self.levelData.enemies[index].wall then
|
||||
self.tiles[tileIndex] = self.levelData.enemies[index].wall + 9
|
||||
else
|
||||
self.tiles[tileIndex] = (self.levelData.enemies[index].floor or 1) + 14
|
||||
end
|
||||
else
|
||||
self.tiles[tileIndex] = 15
|
||||
end
|
||||
elseif r == 0 and g == 0 and b > 0 then
|
||||
local index = 9 - math.ceil(b * 8)
|
||||
if index == 8 then
|
||||
self.player_x = j - 1
|
||||
self.player_y = i - 1
|
||||
if self.levelData.transitions[index] then
|
||||
if self.levelData.transitions[index].door then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].door + 18
|
||||
elseif self.levelData.transitions[index].tile then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].tile + 14
|
||||
end
|
||||
end
|
||||
elseif self.levelData.transitions[index] then
|
||||
if self.levelData.transitions[index].door then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].door + 18
|
||||
elseif self.levelData.transitions[index].tile then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].tile + 14
|
||||
end
|
||||
if not connectionOffsets[index] then
|
||||
connectionOffsets[index] = { j - 1, i - 1 }
|
||||
end
|
||||
|
||||
local transition = self.levelData.transitions[index]
|
||||
|
||||
if self.levelData.transitions[index].absolute then
|
||||
self.connections[tileIndex] = {
|
||||
x = transition.x,
|
||||
y = transition.y,
|
||||
map = transition.map,
|
||||
}
|
||||
else
|
||||
self.connections[tileIndex] = {
|
||||
x = transition.x + (j - connectionOffsets[index][1]) - 1,
|
||||
y = transition.y + (i - connectionOffsets[index][2]) - 1,
|
||||
map = transition.map,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.levelData.enemies[index] then
|
||||
local enemy = self.levelData.enemies[index].data.new((x - 1) * self.tile_width, (y - 1) * self.tile_height)
|
||||
if self.levelData.enemies[index].props then
|
||||
for k,v in pairs(self.levelData.enemies[index].props) do
|
||||
print(k.." = "..v)
|
||||
enemy[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO
|
||||
self.levelData.enemy_system:add(enemy)
|
||||
|
||||
if self.levelData.enemies[index].wall then
|
||||
self.tiles[tileIndex] = self.levelData.enemies[index].wall + 9
|
||||
else
|
||||
self.tiles[tileIndex] = (self.levelData.enemies[index].floor or 1) + 14
|
||||
end
|
||||
else
|
||||
self.tiles[tileIndex] = 15
|
||||
end
|
||||
end)
|
||||
|
||||
-- Connections
|
||||
api:register_color({0, 0, 1}, function(self, x, y, value, data)
|
||||
local tileIndex = (y - 1) * self.width + x
|
||||
self.tiles[tileIndex] = 0
|
||||
|
||||
local index = 9 - math.ceil(value * 8)
|
||||
if index == 8 then
|
||||
self.player_x = x - 1
|
||||
self.player_y = y - 1
|
||||
if self.levelData.transitions[index] then
|
||||
if self.levelData.transitions[index].door then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].door + 18
|
||||
elseif self.levelData.transitions[index].tile then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].tile + 14
|
||||
end
|
||||
end
|
||||
elseif self.levelData.transitions[index] then
|
||||
if self.levelData.transitions[index].door then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].door + 18
|
||||
elseif self.levelData.transitions[index].tile then
|
||||
self.tiles[tileIndex] = self.levelData.transitions[index].tile + 14
|
||||
end
|
||||
if not self.connectionOffsets[index] then
|
||||
self.connectionOffsets[index] = { x - 1, y - 1 }
|
||||
end
|
||||
|
||||
local transition = self.levelData.transitions[index]
|
||||
|
||||
if self.levelData.transitions[index].absolute then
|
||||
self.connections[tileIndex] = {
|
||||
x = transition.x,
|
||||
y = transition.y,
|
||||
map = transition.map,
|
||||
}
|
||||
else
|
||||
self.connections[tileIndex] = {
|
||||
x = transition.x + (x - self.connectionOffsets[index][1]) - 1,
|
||||
y = transition.y + (y - self.connectionOffsets[index][2]) - 1,
|
||||
map = transition.map,
|
||||
}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Autotiles
|
||||
api:register_post_load(function(self, image, data)
|
||||
self.quads = {}
|
||||
|
||||
for i,t in ipairs(self.tiles) do
|
||||
local x = (i - 1) % self.width
|
||||
local y = math.floor((i - 1) / self.width)
|
||||
|
||||
if t >= 10 then
|
||||
self.quads[i] = self.tilesets[t - 9].func(self.tilesets[t - 9], self:getAdjacentTiles(x, y), self.tilesets[t - 9].args)
|
||||
self.quads[i] = self.tilesets[t - 9].func(self.tilesets[t - 9], level.getAdjacentTiles(self, x, y), self.tilesets[t - 9].args)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function level.init(self, filename, enemies)
|
||||
enemies:clear()
|
||||
|
||||
local level_data = require("levels/" .. filename)
|
||||
level_data.enemy_system = enemies
|
||||
local loaded_level = self.api:load(love.image.newImageData("levels/" .. level_data.map), level_data)
|
||||
|
||||
for k,v in pairs(loaded_level) do
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- OLD CODE
|
||||
|
||||
function level.draw(self)
|
||||
for i,t in ipairs(self.tiles) do
|
||||
local x = (i - 1) % self.width
|
||||
@ -172,9 +188,9 @@ end
|
||||
|
||||
function level.getAdjacentTiles(self, x, y)
|
||||
return {
|
||||
self:getTile(x - 1, y - 1), self:getTile(x, y - 1), self:getTile(x + 1, y - 1),
|
||||
self:getTile(x - 1, y), self:getTile(x, y), self:getTile(x + 1, y),
|
||||
self:getTile(x - 1, y + 1), self:getTile(x, y + 1), self:getTile(x + 1, y + 1),
|
||||
level.getTile(self, x - 1, y - 1), level.getTile(self, x, y - 1), level.getTile(self, x + 1, y - 1),
|
||||
level.getTile(self, x - 1, y), level.getTile(self, x, y), level.getTile(self, x + 1, y),
|
||||
level.getTile(self, x - 1, y + 1), level.getTile(self, x, y + 1), level.getTile(self, x + 1, y + 1),
|
||||
}
|
||||
end
|
||||
function level.getTileCollision(self, x, y)
|
||||
|
104
level_api.lua
Normal file
104
level_api.lua
Normal file
@ -0,0 +1,104 @@
|
||||
-------
|
||||
-- Simple API for loading levels from image files
|
||||
-- @module level_api
|
||||
-- @alias level
|
||||
-- @author Hugues Russ
|
||||
|
||||
local level = {
|
||||
colors = {
|
||||
[1] = {}, -- Red
|
||||
[2] = {}, -- Green
|
||||
[3] = {}, -- Yellow
|
||||
[4] = {}, -- Blue
|
||||
[5] = {}, -- Magenta
|
||||
[6] = {}, -- Cyan
|
||||
[7] = {}, -- White
|
||||
},
|
||||
|
||||
pre_load = {},
|
||||
post_load = {},
|
||||
}
|
||||
|
||||
--- Register a callback to perform on pixels of a certain color channel.
|
||||
-- The function will receive the average value of the color in a range from 0-1
|
||||
-- @param self
|
||||
-- @param channels A table of three numbers of 1 or 0. (eg. `{ 1, 1, 1 }` = white, `{ 0, 1, 0 }` = green)
|
||||
-- @param handle_color The color callback (eg. `function on_color(self, x, y, value, level_data)`)
|
||||
function level.register_color(self, channels, handle_color)
|
||||
local channel = (channels[1] * 1) + (channels[2] * 2) + (channels[3] * 4)
|
||||
table.insert(self.colors[channel], handle_color)
|
||||
end
|
||||
|
||||
--- Register a callback to perform before loading a level.
|
||||
-- This is useful for initialization
|
||||
-- @param self
|
||||
-- @param pre_load The pre-load callback (eg. function `on_pre_load(self, level_image, level_data)`)
|
||||
function level.register_pre_load(self, pre_load)
|
||||
table.insert(self.pre_load, pre_load)
|
||||
end
|
||||
|
||||
--- Register a callback to perform before after a level.
|
||||
-- This is useful for cleanup and registering loaded data
|
||||
-- @param self
|
||||
-- @param post_load The post-load callback (eg. `function on_post_load(self, level_image, level_data)`)
|
||||
function level.register_post_load(self, post_load)
|
||||
table.insert(self.post_load, post_load)
|
||||
end
|
||||
|
||||
--- Load a level from an image file and data table
|
||||
-- @param self
|
||||
-- @param image An image representing the level
|
||||
-- @param data A table containing additional data to pass to callbacks
|
||||
-- @return A table representing the loaded level
|
||||
function level.load(self, image, data)
|
||||
local level_table = {}
|
||||
|
||||
for _,fn in ipairs(self.pre_load) do
|
||||
fn(level_table, image, data)
|
||||
end
|
||||
|
||||
local width, height = image:getDimensions()
|
||||
|
||||
for i=1,height do
|
||||
for j=1,width do
|
||||
-- Determine the channel from rgb
|
||||
local r, g, b = image:getPixel(j - 1, i - 1)
|
||||
local channel = 0
|
||||
local count = 0
|
||||
local value = 0
|
||||
if r ~= 0 then
|
||||
channel = channel + 1
|
||||
count = count + 1
|
||||
value = value + r
|
||||
end
|
||||
if g ~= 0 then
|
||||
channel = channel + 2
|
||||
count = count + 1
|
||||
value = value + g
|
||||
end
|
||||
if b ~= 0 then
|
||||
channel = channel + 4
|
||||
count = count + 1
|
||||
value = value + b
|
||||
end
|
||||
if channel == 0 then
|
||||
channel = 7
|
||||
count = 3
|
||||
value = r + g + b
|
||||
end -- Black = White channel
|
||||
|
||||
-- Handle each callback for the selected channel
|
||||
for _,fn in ipairs(self.colors[channel]) do
|
||||
fn(level_table, j, i, value / count, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _,fn in ipairs(self.post_load) do
|
||||
fn(level_table, image, data)
|
||||
end
|
||||
|
||||
return level_table
|
||||
end
|
||||
|
||||
return level
|
Loading…
x
Reference in New Issue
Block a user