From 4761446e730aeec03bc005bffd8f6b1fda0ecd80 Mon Sep 17 00:00:00 2001 From: PeaAshMeter Date: Mon, 13 Apr 2026 03:20:50 +0300 Subject: [PATCH] - add boar - implement manifests for sprites - fix sprite and shadowcaster draw algorithm --- assets/{sprites/boar => }/boar.png | Bin assets/sprites/boar/manifest.lua | 9 +++++++ assets/sprites/boar/sheets/idle.png | Bin 0 -> 1416 bytes assets/sprites/boar/sheets/run.png | Bin 0 -> 2198 bytes assets/sprites/character/manifest.lua | 9 +++++++ .../sprites/character/{ => sheets}/attack.png | Bin .../sprites/character/{ => sheets}/hurt.png | Bin .../sprites/character/{ => sheets}/idle.png | Bin assets/sprites/character/{ => sheets}/run.png | Bin lib/character/behaviors/shadowcaster.lua | 16 ++++++------ lib/character/behaviors/sprite.lua | 23 ++++++++++-------- main.lua | 11 +++++++++ 12 files changed, 51 insertions(+), 17 deletions(-) rename assets/{sprites/boar => }/boar.png (100%) create mode 100644 assets/sprites/boar/manifest.lua create mode 100644 assets/sprites/boar/sheets/idle.png create mode 100644 assets/sprites/boar/sheets/run.png create mode 100644 assets/sprites/character/manifest.lua rename assets/sprites/character/{ => sheets}/attack.png (100%) rename assets/sprites/character/{ => sheets}/hurt.png (100%) rename assets/sprites/character/{ => sheets}/idle.png (100%) rename assets/sprites/character/{ => sheets}/run.png (100%) diff --git a/assets/sprites/boar/boar.png b/assets/boar.png similarity index 100% rename from assets/sprites/boar/boar.png rename to assets/boar.png diff --git a/assets/sprites/boar/manifest.lua b/assets/sprites/boar/manifest.lua new file mode 100644 index 0000000..329cd9e --- /dev/null +++ b/assets/sprites/boar/manifest.lua @@ -0,0 +1,9 @@ +return { + width = 32, + height = 32, + base = { + x = 14, + y = 26 + }, + size = 0.6 -- условная доля тайла, которую занимает спрайт +} diff --git a/assets/sprites/boar/sheets/idle.png b/assets/sprites/boar/sheets/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..defff43549f51e1808a734981d6804128b91c489 GIT binary patch literal 1416 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 --- @field animationGrid table +--- @field manifest table +--- @field sheets table --- @field state "idle"|"run"|"hurt"|"attack" --- @field side 1|-1 local sprite = {} @@ -17,11 +19,12 @@ function sprite.new(spriteDir) local anim = setmetatable({}, sprite) anim.animationTable = {} anim.animationGrid = {} - + anim.manifest = spriteDir.manifest + anim.sheets = spriteDir.sheets -- 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) + for n, i in pairs(spriteDir.sheets) do + local aGrid = anim8.newGrid(anim.manifest.width, anim.manifest.height, i:getWidth(), i:getHeight()) + local tiles = '1-' .. math.ceil(i:getWidth() / anim.manifest.width) anim.animationGrid[n] = aGrid(tiles, 1) end @@ -39,7 +42,7 @@ function sprite:update(dt) end function sprite:draw() - if not self.animationTable[self.state] or not Tree.assets.files.sprites.character[self.state] then return end + if not self.animationTable[self.state] or not self.sheets[self.state] then return end self.owner:try(Tree.behaviors.positioned, function(pos) @@ -51,16 +54,16 @@ function sprite:draw() 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 texW, texH = self.sheets[self.state]:getWidth(), + self.sheets[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], + self.animationTable[self.state]:draw(self.sheets[self.state], position.x, - position.y, nil, 1 / ppm * self.side, 1 / ppm, 38, 47) + position.y, nil, 1 / ppm * self.side, 1 / ppm, self.manifest.base.x, self.manifest.base.y) love.graphics.setShader() Tree.level.camera:detach() @@ -74,7 +77,7 @@ function sprite:animate(state) return function(callback) if not self.animationGrid[state] then print("[SpriteBehavior]: no animation for '" .. state .. "'") - callback() + return callback() end self.animationTable[state] = anim8.newAnimation(self.animationGrid[state], self.ANIMATION_SPEED, function() diff --git a/main.lua b/main.lua index 25db8f6..a657dc8 100644 --- a/main.lua +++ b/main.lua @@ -56,6 +56,17 @@ function love.load() Tree.behaviors.spellcaster.new(), Tree.behaviors.ai.new() }, + character.spawn("BOAR") + :addBehavior { + Tree.behaviors.residentsleeper.new(), + Tree.behaviors.stats.new(nil, nil, 2), + Tree.behaviors.positioned.new(Vec3 { 7, 7 }), + Tree.behaviors.tiled.new(), + Tree.behaviors.sprite.new(Tree.assets.files.sprites.boar), + Tree.behaviors.shadowcaster.new(), + Tree.behaviors.spellcaster.new(), + Tree.behaviors.ai.new() + }, } for id, _ in pairs(chars) do