local anim8 = require "lib.utils.anim8" --- @class SpriteBehavior : Behavior --- @field animationTable 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 } 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 love.graphics.setCanvas(Tree.level.render.shadowLayer) love.graphics.setColor(0, 0, 0, 0.5) love.graphics.ellipse("fill", position.x, position.y, 0.2, 0.2 * math.cos(math.pi / 4)) local mesh = makeGradientMesh(0.4, 1.5, { 0, 0, 0, 0.5 }, { 0, 0, 0, 0 }) love.graphics.push() love.graphics.translate(position.x, position.y) love.graphics.rotate(love.timer.getTime()) love.graphics.translate(-0.2, 0) love.graphics.draw(mesh) love.graphics.pop() love.graphics.setCanvas(Tree.level.render.spriteLayer) love.graphics.setColor(1, 1, 1) 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