119 lines
4.2 KiB
Lua
119 lines
4.2 KiB
Lua
local anim8 = require "lib.utils.anim8"
|
|
|
|
--- @class SpriteBehavior : Behavior
|
|
--- @field animationTable table<string, table>
|
|
--- @field animationGrid table
|
|
--- @field state "idle"|"run"|"hurt"|"attack"
|
|
--- @field side 1|-1
|
|
local sprite = {}
|
|
sprite.__index = sprite
|
|
sprite.id = "sprite"
|
|
sprite.LEFT = -1
|
|
sprite.RIGHT = 1
|
|
--- Скорость между кадрами в анимации
|
|
sprite.ANIMATION_SPEED = 0.1
|
|
|
|
function sprite.new(spriteDir)
|
|
local anim = setmetatable({}, sprite)
|
|
anim.animationTable = {}
|
|
anim.animationGrid = {}
|
|
|
|
-- n: name; i: image
|
|
for n, i in pairs(spriteDir) do
|
|
local aGrid = anim8.newGrid(96, 64, i:getWidth(), i:getHeight())
|
|
local tiles = '1-' .. math.ceil(i:getWidth() / 96)
|
|
anim.animationGrid[n] = aGrid(tiles, 1)
|
|
end
|
|
|
|
anim.state = "idle"
|
|
anim.side = sprite.RIGHT
|
|
anim:loop("idle")
|
|
return anim
|
|
end
|
|
|
|
function sprite:update(dt)
|
|
local anim = self.animationTable[self.state] or self.animationTable["idle"] or nil
|
|
|
|
if not anim then return end
|
|
anim:update(dt)
|
|
end
|
|
|
|
local function makeGradientMesh(w, h, topColor, bottomColor)
|
|
local vertices = {
|
|
{ 0, 0, 0, 0, topColor[1], topColor[2], topColor[3], topColor[4] }, -- левый верх
|
|
{ w, 0, 1, 0, topColor[1], topColor[2], topColor[3], topColor[4] }, -- правый верх
|
|
{ w + w * 0.1, h, 1, 1, bottomColor[1], bottomColor[2], bottomColor[3], bottomColor[4] }, -- правый низ
|
|
{ 0 - w * 0.1, h, 0, 1, bottomColor[1], bottomColor[2], bottomColor[3], bottomColor[4] }, -- левый низ
|
|
}
|
|
local mesh = love.graphics.newMesh(vertices, "fan", "static")
|
|
return mesh
|
|
end
|
|
|
|
function sprite:draw()
|
|
if not self.animationTable[self.state] or not Tree.assets.files.sprites.character[self.state] then return end
|
|
|
|
self.owner:try(Tree.behaviors.map,
|
|
function(map)
|
|
local ppm = Tree.level.camera.pixelsPerMeter
|
|
local position = map.displayedPosition + Vec3 { 0.5, 0.5 }
|
|
|
|
Tree.level.camera:detach()
|
|
|
|
love.graphics.push()
|
|
love.graphics.scale(ppm)
|
|
love.graphics.setCanvas(Tree.level.render.shadowLayer)
|
|
love.graphics.setColor(0, 0, 0, 0.5)
|
|
love.graphics.translate(position.x, position.y)
|
|
love.graphics.ellipse("fill", 0, 0, 0.2, 0.2 * math.cos(math.pi / 4))
|
|
|
|
love.graphics.rotate(math.pi / 4)
|
|
|
|
self.animationTable[self.state]:draw(Tree.assets.files.sprites.character[self.state],
|
|
0,
|
|
0, nil, 1 / ppm * self.side, 1.2 / ppm, 38, 47)
|
|
love.graphics.pop()
|
|
|
|
Tree.level.camera:attach()
|
|
|
|
love.graphics.setCanvas(Tree.level.render.spriteLayer)
|
|
love.graphics.setColor(1, 1, 1)
|
|
if Tree.level.selector.id == self.owner.id then
|
|
local texW, texH = Tree.assets.files.sprites.character[self.state]:getWidth(),
|
|
Tree.assets.files.sprites.character[self.state]:getHeight()
|
|
local shader = Tree.assets.files.shaders.outline
|
|
shader:send("texSize", { texW, texH })
|
|
shader:send("time", love.timer:getTime())
|
|
love.graphics.setShader(shader)
|
|
end
|
|
self.animationTable[self.state]:draw(Tree.assets.files.sprites.character[self.state],
|
|
position.x,
|
|
position.y, nil, 1 / ppm * self.side, 1 / ppm, 38, 47)
|
|
love.graphics.setShader()
|
|
love.graphics.setCanvas()
|
|
end
|
|
)
|
|
end
|
|
|
|
--- @param node AnimationNode
|
|
function sprite:animate(state, node)
|
|
if not self.animationGrid[state] then
|
|
return print("[SpriteBehavior]: no animation for '" .. state .. "'")
|
|
end
|
|
self.animationTable[state] = anim8.newAnimation(self.animationGrid[state], self.ANIMATION_SPEED,
|
|
function()
|
|
self:loop("idle")
|
|
node:finish()
|
|
end)
|
|
self.state = state
|
|
end
|
|
|
|
function sprite:loop(state)
|
|
if not self.animationGrid[state] then
|
|
return print("[SpriteBehavior]: no animation for '" .. state .. "'")
|
|
end
|
|
self.animationTable[state] = anim8.newAnimation(self.animationGrid[state], self.ANIMATION_SPEED)
|
|
self.state = state
|
|
end
|
|
|
|
return sprite
|