Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Reference:
- Сетка спрайтов вида:
- _|1|2|3|4|
- 1|x|x|x|x|
- 2|x|x|N|x|
- 3|x|x|x|x|,
- Где спрайт N имеет координаты 3, 2, если считать позицию по сетке,
- или 7, если считать последовательно.
- Создание сетки:
- list = grid(image, 4, 3)
- ]]
- local function err(v, lvl, ...)
- error(v:format(...), lvl)
- end
- local min, max, floor, ceil, sin, cos = math.min, math.max, math.floor, math.ceil, math.sin, math.cos
- local graphics = love.graphics
- grid = {} -- Spritegrid class
- local animated = {} -- Assisted class, represent animated object
- local static = {} -- Assisted class, represent static object
- setmetatable(grid, {
- __call = function(self, img, sx, sy, mx, my) -- img - image, sx & sy - sprite count in grid
- local o = {img = img}
- o.batch = graphics.newSpriteBatch(o.img, 20000)
- o.batchfree = {} -- Free id for reusing
- o.animation = {} -- Animations list
- o.sx = sx or 1 -- One by default
- o.sy = sy or 1
- local imgx, imgy = o.img:getDimensions()
- local mx, my = mx or 0, my or 0 -- margin
- o.sw, o.sh = floor(imgx / o.sx), floor(imgy / o.sy) -- One sprite dimensions
- o.quad = {} -- Quad list
- for j = 0, o.sy-1 do
- for i = 0, o.sx-1 do
- table.insert(o.quad, graphics.newQuad(i*o.sw + mx, j*o.sh + my, o.sw - mx*2, o.sh - my*2, imgx, imgy))
- end
- end
- self.__index = self
- return setmetatable(o, {__index = self})
- end
- })
- local function checkSequence(t, maxX, maxY)
- local count = maxX * maxX
- for i, position in ipairs(t) do
- if position < 1 or position > count then
- err('Grid:newAnimation error: %d sprite not found, grid dimensions: [%d, %d]', 3, i, maxX, maxY)
- end
- end
- return t
- end
- local function linearize(t, y)
- local buf = {}
- if type(t[1]) == 'table' then
- for i, v in ipairs(t) do
- table.insert(buf, v[1] + (v[2]-1)*y)
- end
- end
- return #buf > 0 or t
- end
- function grid:newAnimation(name, t, time, loop)
- self.animation[name] = {
- seq = checkSequence(linearize(t, self.sy), self.sx, self.sy),
- count = #t,
- delay = time/#t,
- loop = loop
- }
- end
- function grid:getQuad(x, y)
- return y and self.quad[(y-1)*self.sy+x] --вычисление позиции квада в списке
- or self.quad[x]
- end
- function grid:getFreeSequence(n, count)
- local s, seq = 0, 0
- for i, v in ipairs(table.sort(self.batchfree)) do
- seq = s == (v - 1) and seq + 1 or 0
- s = v
- if seq == count then return v - count end
- end
- end
- function grid:add(n, ...)
- if #self.batchfree > 0 then
- table.sort(self.batchfree)
- print('reuse sprite')
- return self.batchfree[1], self.batch:set(self.batchfree[1], n and self.quad[n] or self.quad[1], ...), table.remove(self.batchfree, 1)
- end
- return self.batch:add(n and self.quad[n] or self.quad[1], ...)
- end
- function grid:free(n)
- table.insert(self.batchfree, n)
- self.batch:set(n, 0, 0, 0, 0, 0)
- end
- function grid:update(id, name, time, ...)
- self.batch:setColor(graphics.getColor())
- local a = self.animation[name]
- local x, y = 1, 1
- local n = a.loop and a.seq[ ceil( time / a.delay % a.count)]
- or a.seq[min(ceil( time / a.delay), a.count)]
- or 1
- self.batch:set(id, self:getQuad(n), ...)
- end
- function grid:set(id, n, ...)
- self.batch:set(id, self:getQuad(n), ...)
- end
- function grid:getDimensions()
- return self.sw, self.sh
- end
- function grid:newDynamic(...)
- return animated(self, ...)
- end
- function grid:newStatic(n, ...)
- return static(self, n, ...)
- end
- function grid:draw(...)
- collectgarbage()
- graphics.draw(self.batch, ...)
- end
- local function mt__gc(t, mt) --collect garbage method trick
- local mt = mt or getmetatable(t)
- local prox = newproxy(true)
- getmetatable(prox).__gc = function() mt.__gc(t) end
- t[prox] = true
- print('proxy')
- return setmetatable(t, mt)
- end
- setmetatable(animated, {
- __call = function(self, grid, default, ...) -- grid as grid, t as table with sprite sequense, time as anim length and loop flag
- local o = {timer = 0, grid = grid}
- print(unpack({...}))
- o.id = o.grid:add(1, ...)
- o.name = default
- self.__index = self
- return mt__gc(o, {__index = self, __gc = function() o.grid:free(o.id) end})
- end
- })
- function animated:set(name)
- self.timer = 0
- self.name = name
- end
- function animated:setSprite(n)
- self.timer = self.grid.animation[self.name].delay*n
- end
- function animated:get()
- return self.name, self.timer
- end
- function animated:getSize()
- return self.grid:getSize()
- end
- function animated:update(dt, ...)
- if self.name then
- self.timer = self.timer + dt
- end
- self.grid:update(self.id, self.name, self.timer, ...)
- end
- setmetatable(static, {
- __call = function(self, grid, sprite, ...) -- grid as grid, t as table with sprite sequense, time as anim length and loop flag
- local o = {grid = grid, sprite = sprite}
- o.id = o.grid:add(sprite, ...)
- self.__index = self
- return mt__gc(o, {__index = self, __gc = function() o.grid:free(o.id) end})
- end
- })
- function static:set(n)
- self.sprite = n
- end
- function static:update(dt, ...)
- self.grid:set(self.id, self.sprite, ...)
- end
- local t = {
- body = {type = 'static', state = 2, x = 10, y = 20, w = 30, h = 20, r = 0.3, sx = 35, sy = 20},
- lefthand = {type = 'dynamic', state = 'wawa', x = 10, y = 20, w = 30, h = 20, r = 0.3, sx = 35, sy = 20},
- {drawable, x, y, r, sx, sy, ox, oy, kx, ky }
- }
- local function drawunpack(t)
- return t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9]
- end
- local function rewrite(t1, t2)
- for i, v in ipairs(t2) do t1[i] = t2[i] or t1[i] end
- return t1
- end
- local mapping = {x = 1, y = 2, r = 3, sx = 4, sy = 5, ox = 6, oy = 7, kx = 8, ky = 9}
- local backmap = {'x', 'y', 'r', 'sx', 'sy', 'ox', 'oy', 'kx', 'ky'}
- local default = {x = 0, y = 0, r = 0, sx = 1, sy = 1, ox = 0, oy = 0, kx = 0, ky = 0}
- local function setPos(...)
- local t = {}
- local m = {...}
- for i = 1, #backmap do
- t[backmap[i]] = m[i] or default[backmap[i]]
- end
- return t
- end
- posMT = function(...)
- local o = {0,0,0,1,1,0,0,0,0}
- return setmetatable(rewrite(o, {...}), {
- __index = function(self, key) return self[mapping[key]] end,
- __newindex = function(self, key, value) if mapping[key] then self[mapping[key]] = value else self[key] = value end end})
- end
- local st = {0,0,0,1,1,0,0,0,0}
- animatedObject = {}
- setmetatable(animatedObject, {
- __call = function(self, ...)
- local o = setPos(...)
- o.flipped = {x = 1, y = 1}
- o.item = {}
- self.__index = self
- return mt__gc(o, {__index = self})
- end
- })
- function animatedObject:getItemPosition(v)
- local flip = self.flipped
- return flip.x and self.x + (self.w + v.x)*self.sx or self.x + v.x*self.sx,
- flip.y and self.y + (self.h + v.y)*self.sy or self.y + v.y*self.sy,
- self.r + v.r,
- flip.x and -self.sx or self.sx,
- flip.y and -self.sy or self.sy,
- v.ox,
- v.oy
- end
- function animatedObject:addItem(n, grid, state, default, ...)
- if type(n) == 'string' then
- self.item[name] = setPos(...)
- v = self.item[name]
- v.w, v.h = grid:getDimensions()
- if not self.w or not self.h then self.w, self.h = grid:getDimensions() end
- v.sprite = state == 'static' and grid:newStatic(1, self:getItemPosition(v))
- or state == 'dynamic' and grid:newDynamic(default, self:getItemPosition(v))
- elseif type(n) == 'table' then
- self.item[n.name] = setPos(n.x or 0, n.y or 0, n.r or 0, n.sx or 1, n.sy or 1, n.ox or 0, n.oy or 0, n.kx or 0, n.ky or 0)
- v = self.item[n.name]
- v.w, v.h = n.grid:getDimensions()
- if not self.w or not self.h then self.w, self.h = v.w, v.h end
- v.sprite = n.type == 'static' and n.grid:newStatic(n.default, self:getItemPosition(v))
- or n.type == 'dynamic' and n.grid:newDynamic(n.default, self:getItemPosition(v))
- end
- end
- function animatedObject:flip(ord, v)
- ord = ord or 'x'
- self.flipped[ord] = v
- end
- function animatedObject:update(dt, x, y, r, sx, sy, ox, oy) --обновление позиции
- self.x = x or self.x
- self.y = y or self.y
- self.r = r or self.r
- self.sx = sx or 1
- self.sy = sy or 1
- self.ox = ox or 0
- self.oy = oy or 0
- local flip = self.flip
- for k, item in pairs(self.item) do
- item.sprite:update(dt, self:getItemPosition(item)) -- dt - дельта времени, для анимаций, таймлайнов и всего такого
- end
- end
- function animatedObject:draw() -- отрисовка для дебага (если спрайт пуст - нарисует bounding box)
- for k, v in pairs(self.item) do
- love.graphics.rectangle(
- 'line',
- self.flip and self.x + v.x + self.w - v.ox or self.x + v.x + v.ox,
- self.flip and self.y + v.y + self.h - v.oy or self.y + v.y + v.oy,
- self.flip and -v.w or v.w,
- self.flip and -v.h or v.h)
- end
- end
- function animatedObject:setAnimation(item, animation)
- self.item[item].sprite:set(animation)
- end
- function grid:newObject(...)
- return animatedObject(...)
- end
- return grid
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement