migrate spells to AnimationNode api

This commit is contained in:
PeaAshMeter 2025-10-23 18:58:34 +03:00
parent 6faf7f1c1d
commit 77e723c4bb
2 changed files with 47 additions and 69 deletions

View File

@ -27,7 +27,7 @@ function sprite.new(spriteDir)
anim.state = "idle" anim.state = "idle"
anim.side = sprite.RIGHT anim.side = sprite.RIGHT
anim:play("idle") anim:loop("idle")
return anim return anim
end end
@ -54,20 +54,6 @@ function sprite:draw()
) )
end end
--- @param state string
--- @param loop nil | boolean | fun(): nil
function sprite:play(state, loop)
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,
type(loop) == "function" and loop or
function()
if not loop then self:play("idle", true) end
end)
self.state = state
end
--- @param node AnimationNode --- @param node AnimationNode
function sprite:animate(state, node) function sprite:animate(state, node)
if not self.animationGrid[state] then if not self.animationGrid[state] then

View File

@ -7,7 +7,7 @@
--- --TODO: каждый каст должен возвращать объект, который позволит отследить момент завершения анимации спелла --- --TODO: каждый каст должен возвращать объект, который позволит отследить момент завершения анимации спелла
--- Да, это Future/Promise/await/async --- Да, это Future/Promise/await/async
local Animation = require "lib.animation_node" local AnimationNode = require "lib.animation_node"
--- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell --- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла --- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
@ -40,44 +40,18 @@ function walk:cast(caster, target)
for p in path:values() do print(p) end for p in path:values() do print(p) end
Animation {
function(node) caster:has(Tree.behaviors.sprite):animate("hurt", node) end,
onEnd = function() caster:has(Tree.behaviors.spellcaster):endCast() end,
children = {
Animation {
function(node)
caster:has(Tree.behaviors.sprite):loop('idle')
caster:has(Tree.behaviors.residentsleeper):sleep(1000, node)
end,
children = {
Animation {
function(node)
caster:has(Tree.behaviors.map):followPath(path, node)
end,
}
}
},
Animation {
function(node)
Tree.level.characters[2]:has(Tree.behaviors.sprite):animate("hurt", node)
end,
children = {
Animation {
function(node)
local from = Tree.level.characters[2]:has(Tree.behaviors.map).position
local p = (require "lib.pathfinder")(from, Vec3 { 10, 10 })
Tree.level.characters[2]:has(Tree.behaviors.map):followPath(p, node)
end
}
}
}
}
}:run()
caster:try(Tree.behaviors.stats, function(stats) caster:try(Tree.behaviors.stats, function(stats)
stats.mana = stats.mana - 2 stats.mana = stats.mana - 2
print(stats.mana) print(stats.mana)
end) end)
local sprite = caster:has(Tree.behaviors.sprite)
if not sprite then return true end
AnimationNode {
function(node) caster:has(Tree.behaviors.map):followPath(path, node) end,
onEnd = function() caster:has(Tree.behaviors.spellcaster):endCast() end,
}:run()
return true return true
end end
@ -105,14 +79,15 @@ function regenerateMana:cast(caster, target)
stats.mana = 10 stats.mana = 10
end) end)
print(caster.id, "has regenerated mana") print(caster.id, "has regenerated mana")
caster:try(Tree.behaviors.sprite, function(sprite) -- бойлерплейт (временный) local sprite = caster:has(Tree.behaviors.sprite)
-- В данный момент заклинание не позволяет отслеживать состояние последствий своего применения, так что надо повесить хоть какую-то анимашку просто для того, чтобы отложить завершение каста куда-то в будущее if not sprite then return true end
-- См. также https://learn.javascript.ru/settimeout-setinterval AnimationNode {
sprite:play("hurt", function() function(node)
sprite:play("idle") sprite:animate("hurt", node)
caster:has(Tree.behaviors.spellcaster):endCast() end,
end) onEnd = function() caster:has(Tree.behaviors.spellcaster):endCast() end
end) }:run()
return true return true
end end
@ -135,18 +110,35 @@ function attack:cast(caster, target)
stats.hp = stats.hp - 4 stats.hp = stats.hp - 4
end) end)
caster:try(Tree.behaviors.sprite, function(sprite) local sprite = caster:has(Tree.behaviors.sprite)
sprite:play("attack", function() local targetSprite = targetCharacter:has(Tree.behaviors.sprite)
sprite:play("idle") if not sprite or not targetSprite then return true end
targetCharacter:try(Tree.behaviors.sprite, function(targetSprite)
targetSprite:play("hurt", function()
targetSprite:play("idle")
caster:has(Tree.behaviors.spellcaster):endCast()
end)
end)
end)
end)
AnimationNode {
function(node)
caster:has(Tree.behaviors.residentsleeper):sleep(0, node)
end,
onEnd = function() caster:has(Tree.behaviors.spellcaster):endCast() end,
children = {
AnimationNode {
function(node)
sprite:animate("attack", node)
end
},
AnimationNode {
function(node)
targetCharacter:has(Tree.behaviors.residentsleeper):sleep(200, node)
end,
children = {
AnimationNode {
function(node)
targetSprite:animate("hurt", node)
end
}
}
}
}
}:run()
return true return true
end end