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 -- Util
@ -102,7 +111,7 @@ function Animation:generateImage ()
if self.wrap then t = t % self.duration end if self.wrap then t = t % self.duration end
local quad = get_quad_based_on_time(self, t) 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) love.graphics.draw(self.imagesheet.image, quad, x, y, 0, 1, 1, self.imagesheet.origin_x, self.imagesheet.origin_y)
end end
end end
@ -165,8 +174,8 @@ local function load_quads (image, quad_data, imagesheet)
local image_width, image_height = image:getDimensions() local image_width, image_height = image:getDimensions()
local tile_width, tile_height = quad_data.tile_width, quad_data.tile_height local tile_width, tile_height = quad_data.tile_width, quad_data.tile_height
local tiles_pr_row = image_width/tile_width local tiles_per_row = image_width/tile_width
local max_quad_id = tiles_pr_row * (image_height/tile_height) - 1 local max_quad_id = tiles_per_row * (image_height/tile_height) - 1
local quad_cache = {} local quad_cache = {}
local function quad_from_id (id) local function quad_from_id (id)
@ -177,7 +186,7 @@ local function load_quads (image, quad_data, imagesheet)
-- Calculate -- Calculate
if not quad_cache[id] then 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 end
return quad_cache[id] return quad_cache[id]
end end
@ -226,15 +235,40 @@ local function load_quad_data (filename)
local chunk, error_msg = love.filesystem.load(filename..'.lua') local chunk, error_msg = love.filesystem.load(filename..'.lua')
if chunk then if chunk then
local data = setfenv(chunk, SPRITESHEET_ENV)() local data = setfenv(chunk, SPRITESHEET_ENV)()
-- Error check -- 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) ~= 'table' then
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 error('Bad spritesheet "%s". Must return a table, but returned %s (%s)', filename, data, type(data))
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 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 local l = {'Bad spritesheet "'.. filename.. '"'}
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 data.tiles_per_row ~= nil and data.tile_width ~= nil then
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 l[#l+1] = 'Root table must not contain both keys "tiles_per_row" and "tile_width"'
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 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 return data
end end
print(error_msg) print(error_msg)
@ -253,18 +287,38 @@ local SpriteSheet = {}
function SpriteSheet.new (filename) function SpriteSheet.new (filename)
local quad_data = load_quad_data(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 -- Set info
local self = setmetatable({}, SpriteSheet) local self = setmetatable({}, SpriteSheet)
self.filename = filename self.filename = filename
self.image = love.graphics.newImage(filename..'.png') self.image = love.graphics.newImage(filename..'.png')
self.origin_x = 0 self.origin_x = 0
self.origin_y = 0 self.origin_y = 0
self.tile_width = quad_data.tile_width
self.tile_height = quad_data.tile_height -- 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 -- 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 do
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 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 -- Set origin
if quad_data.tile_origin then if quad_data.tile_origin then