1
0

Added several convenience features.

Including allowing specifying number of tiles for each dimension, if for
example it is known that the image will contain 16x16 sprites, but the
size of the individual sprite is unknown.
This commit is contained in:
Jon Michael Aanes 2019-12-04 18:11:11 +01:00
parent 69f0d85100
commit bc3752da1b

View File

@ -1,5 +1,14 @@
local error = require 'errors' 'SpriteSheet2'
local error_orig = error
local error, error_internal do
error, error_internal = error_orig, error_orig
error_orig = nil
local success, errorlib = pcall(require,'errors')
if success then
error = errorlib 'spritesheet'
error_internal = error.internal
end
end
--------------------------------------------------------------------------------
-- Util
@ -102,7 +111,7 @@ function Animation:generateImage ()
if self.wrap then t = t % self.duration end
local quad = get_quad_based_on_time(self, t)
if not quad then error.internal('Could not determine quad when drawing animation. Time was %f.', t) end
if not quad then error_internal('Could not determine quad when drawing animation. Time was %f.', t) end
love.graphics.draw(self.imagesheet.image, quad, x, y, 0, 1, 1, self.imagesheet.origin_x, self.imagesheet.origin_y)
end
end
@ -165,8 +174,8 @@ local function load_quads (image, quad_data, imagesheet)
local image_width, image_height = image:getDimensions()
local tile_width, tile_height = quad_data.tile_width, quad_data.tile_height
local tiles_pr_row = image_width/tile_width
local max_quad_id = tiles_pr_row * (image_height/tile_height) - 1
local tiles_per_row = image_width/tile_width
local max_quad_id = tiles_per_row * (image_height/tile_height) - 1
local quad_cache = {}
local function quad_from_id (id)
@ -177,7 +186,7 @@ local function load_quads (image, quad_data, imagesheet)
-- Calculate
if not quad_cache[id] then
quad_cache[id] = love.graphics.newQuad((id%tiles_pr_row)*tile_width, math.floor(id/tiles_pr_row)*tile_height, tile_width, tile_height, image_width, image_height)
quad_cache[id] = love.graphics.newQuad((id%tiles_per_row)*tile_width, math.floor(id/tiles_per_row)*tile_height, tile_width, tile_height, image_width, image_height)
end
return quad_cache[id]
end
@ -226,15 +235,40 @@ local function load_quad_data (filename)
local chunk, error_msg = love.filesystem.load(filename..'.lua')
if chunk then
local data = setfenv(chunk, SPRITESHEET_ENV)()
-- Error check
if type(data) ~= 'table' then error('Bad spritesheet "%s". Must return a table, but returned %s (%s)', filename, data, type(data)) end
if type(data.tile_width) ~= 'number' then error('Bad spritesheet "%s". The root table must contain key "tile_width", with integer value, but it was %s (%s)', filename, data.tile_width, type(data.tile_width)) end
if data.tile_width ~= math.floor(data.tile_width) then error('Bad spritesheet "%s". The root table must contain key "tile_width", with integer value, but it was %f (float)', filename, data.tile_width) end
if type(data.tile_height) ~= 'number' then error('Bad spritesheet "%s". The root table must contain key "tile_height", with integer value, but it was %s (%s)', filename, data.tile_height, type(data.tile_height)) end
if data.tile_height ~= math.floor(data.tile_height) then error('Bad spritesheet "%s". The root table must contain key "tile_height", with integer value, but it was %f (float)', filename, data.tile_height) end
if not (type(data.tile_names) == 'table' or type(data.tile_names) == 'number') then error('Bad spritesheet "%s". The root table must contain key "tile_names", with either a table or a number value, but it was %s (%s)', filename, data.tile_names, type(data.tile_names)) end
if data.tile_origin and type(data.tile_origin) ~= 'table' then error('Bad spritesheet "%s". If the root table contains key "tile_origin", it must be a table value, but it was %s (%s)', filename, data.tile_origin, type(data.tile_origin)) end
--
if type(data) ~= 'table' then
error('Bad spritesheet "%s". Must return a table, but returned %s (%s)', filename, data, type(data))
end
local l = {'Bad spritesheet "'.. filename.. '"'}
if data.tiles_per_row ~= nil and data.tile_width ~= nil then
l[#l+1] = 'Root table must not contain both keys "tiles_per_row" and "tile_width"'
elseif data.tiles_per_row == nil and data.tile_width == nil then
l[#l+1] = 'Root table must contain either keys "tiles_per_row" or "tile_width"'
end
if data.tiles_per_column ~= nil and data.tile_height ~= nil then
l[#l+1] = 'Root table must not contain both keys "tiles_per_column" and "tile_height"'
elseif data.tiles_per_column == nil and data.tile_height == nil then
l[#l+1] = 'Root table must contain either keys "tiles_per_column" or "tile_height"'
end
local INTEGER_TILESET_KEYS = {'tile_width', 'tile_height', 'tiles_per_row', 'tiles_per_column'}
for _, integer_key in ipairs(INTEGER_TILESET_KEYS) do
local v = data[integer_key]
if v and (type(v) ~= 'number' or v % 1 ~= 0) then
l[#l+1] = string.format('Key "%s" in root table must map to integer value, but it was %s (%s)', integer_key, v, type(v))
end
end
if not (type(data.tile_names) == 'table' or type(data.tile_names) == 'number') then
l[#l+1] = string.format('Root table must contain key "tile_names", with either a table or a number value, but it was %s (%s)', data.tile_names, type(data.tile_names))
end
if data.tile_origin and type(data.tile_origin) ~= 'table' then
l[#l+1] = string.format('Key "%s" in root table must map to a table value, but it was %s (%s)', 'tile_origin', data.tile_origin, type(data.tile_origin))
end
-- Throw error or return
if #l > 1 then
error(table.concat(l, '\n '))
end
return data
end
print(error_msg)
@ -253,18 +287,38 @@ local SpriteSheet = {}
function SpriteSheet.new (filename)
local quad_data = load_quad_data(filename)
-- NOTE: `force_uneven_tile_size` in quad_data can be used to
-- ignore the image size-tile size divisibility check. Edit the
-- spriteimage itself if you can, as it will silently ignore
-- several errors.
-- Set info
local self = setmetatable({}, SpriteSheet)
self.filename = filename
self.image = love.graphics.newImage(filename..'.png')
self.origin_x = 0
self.origin_y = 0
-- TODO: Give warning/error due to rounding down.
quad_data.tile_width = quad_data.tile_width or math.floor(self.image:getWidth() / quad_data.tiles_per_row)
quad_data.tile_height = quad_data.tile_height or math.floor(self.image:getHeight() / quad_data.tiles_per_column)
print(self.tile_width, self.tile_height)
self.tile_width = quad_data.tile_width
self.tile_height = quad_data.tile_height
-- Error checking
if self.image:getWidth() % self.tile_width ~= 0 then error('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i), but width leaves a remainder of %i.', filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height, self.image:getWidth() % self.tile_width) end
if self.image:getHeight() % self.tile_height ~= 0 then error('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i), but height leaves a remainder of %i.', filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height, self.image:getHeight() % self.tile_height) end
do
local rem_width = self.image:getWidth() % self.tile_width
local rem_height = self.image:getHeight() % self.tile_height
if not quad_data.force_uneven_tile_size and (rem_width ~= 0 or rem_height ~= 0) then
local s = ('Bad spritesheet "%s". Image size (%i, %i) must be dividable by tile size (%i, %i)')
:format(filename, self.image:getWidth(), self.image:getHeight(), self.tile_width, self.tile_height)
if rem_width ~= 0 then s = s..('\n Width leaves a remainder of %i.'):format(rem_width) end
if rem_height ~= 0 then s = s..('\n Height leaves a remainder of %i.'):format(rem_height) end
error(s)
end
end
-- Set origin
if quad_data.tile_origin then