- implement selector locking when processing a spell (players gonna hate
that) - implement spellcaster state handling
This commit is contained in:
parent
83115e82f8
commit
8bcae25a2e
@ -7,6 +7,7 @@ local utils = require "lib.utils.utils"
|
|||||||
--- @field displayedPosition Vec3 точка, в которой персонаж отображается
|
--- @field displayedPosition Vec3 точка, в которой персонаж отображается
|
||||||
--- @field t0 number время начала движения для анимациии
|
--- @field t0 number время начала движения для анимациии
|
||||||
--- @field path Deque путь, по которому сейчас бежит персонаж
|
--- @field path Deque путь, по которому сейчас бежит персонаж
|
||||||
|
--- @field onWalkEnd nil | fun() : nil Функция, которая будет вызвана по завершению [followPath]
|
||||||
--- @field size Vec3
|
--- @field size Vec3
|
||||||
local mapBehavior = {}
|
local mapBehavior = {}
|
||||||
mapBehavior.__index = mapBehavior
|
mapBehavior.__index = mapBehavior
|
||||||
@ -24,8 +25,9 @@ function mapBehavior.new(position, size)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param path Deque
|
--- @param path Deque
|
||||||
function mapBehavior:followPath(path)
|
function mapBehavior:followPath(path, onEnd)
|
||||||
if path:is_empty() then return end
|
if path:is_empty() then return onEnd() end
|
||||||
|
self.onWalkEnd = onEnd
|
||||||
self.position = self.displayedPosition
|
self.position = self.displayedPosition
|
||||||
self.owner:try(Tree.behaviors.sprite, function(sprite)
|
self.owner:try(Tree.behaviors.sprite, function(sprite)
|
||||||
sprite:play("run", true)
|
sprite:play("run", true)
|
||||||
@ -67,6 +69,10 @@ function mapBehavior:update(dt)
|
|||||||
sprite:play("idle", true)
|
sprite:play("idle", true)
|
||||||
end)
|
end)
|
||||||
self.runTarget = nil
|
self.runTarget = nil
|
||||||
|
if self.onWalkEnd then
|
||||||
|
self.onWalkEnd()
|
||||||
|
self.onWalkEnd = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else -- анимация перемещения не завершена
|
else -- анимация перемещения не завершена
|
||||||
self.displayedPosition = utils.lerp(self.position, self.runTarget, fraction) -- линейный интерполятор
|
self.displayedPosition = utils.lerp(self.position, self.runTarget, fraction) -- линейный интерполятор
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
--- @class SpellcasterBehavior : Behavior
|
--- @class SpellcasterBehavior : Behavior
|
||||||
--- @field spellbook Spell[] собственный набор спеллов персонажа
|
--- @field spellbook Spell[] собственный набор спеллов персонажа
|
||||||
--- @field cast Spell | nil ссылка на активный спелл из спеллбука
|
--- @field cast Spell | nil ссылка на активный спелл из спеллбука
|
||||||
|
--- @field state "idle" | "casting" | "running"
|
||||||
local behavior = {}
|
local behavior = {}
|
||||||
behavior.__index = behavior
|
behavior.__index = behavior
|
||||||
behavior.id = "spellcaster"
|
behavior.id = "spellcaster"
|
||||||
|
behavior.state = "idle"
|
||||||
|
|
||||||
---@param spellbook Spell[] | nil
|
---@param spellbook Spell[] | nil
|
||||||
---@return SpellcasterBehavior
|
---@return SpellcasterBehavior
|
||||||
@ -14,12 +16,18 @@ function behavior.new(spellbook)
|
|||||||
return setmetatable(t, behavior)
|
return setmetatable(t, behavior)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function behavior:endCast()
|
||||||
|
self.state = "idle"
|
||||||
|
self.cast = nil
|
||||||
|
Tree.level.selector:unlock()
|
||||||
|
end
|
||||||
|
|
||||||
function behavior:update(dt)
|
function behavior:update(dt)
|
||||||
if self.cast then self.cast:update(self.owner, dt) end
|
if self.cast and self.state == "casting" then self.cast:update(self.owner, dt) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function behavior:draw()
|
function behavior:draw()
|
||||||
if self.cast then self.cast:draw() end
|
if self.cast and self.state == "casting" then self.cast:draw() end
|
||||||
end
|
end
|
||||||
|
|
||||||
return behavior
|
return behavior
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
--- @class Selector
|
--- @class Selector
|
||||||
--- @field id Id | nil
|
--- @field id Id | nil
|
||||||
|
--- @field locked boolean
|
||||||
local selector = {}
|
local selector = {}
|
||||||
selector.__index = selector
|
selector.__index = selector
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ function selector:select(characterId)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function selector:update(dt)
|
function selector:update(dt)
|
||||||
if not Tree.controls:isJustPressed("select") then return end
|
if self.locked or not Tree.controls:isJustPressed("select") then return end
|
||||||
|
|
||||||
local mousePosition = Tree.level.camera:toWorldPosition(Vec3 { love.mouse.getX(), love.mouse.getY() }):floor()
|
local mousePosition = Tree.level.camera:toWorldPosition(Vec3 { love.mouse.getX(), love.mouse.getY() }):floor()
|
||||||
|
|
||||||
@ -32,12 +33,25 @@ function selector:update(dt)
|
|||||||
self:select(selectedId)
|
self:select(selectedId)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
b.cast:cast(char, mousePosition)
|
if b.cast:cast(char, mousePosition) then
|
||||||
b.cast = nil
|
self:lock()
|
||||||
|
b.state = "running"
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Disables the selector until [unlock] is called
|
||||||
|
function selector:lock()
|
||||||
|
self.id = nil
|
||||||
|
self.locked = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Cancels the effect of [lock]
|
||||||
|
function selector:unlock()
|
||||||
|
self.locked = false
|
||||||
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
new = new
|
new = new
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
--- @class Spell
|
--- @class Spell Здесь будет много бойлерплейта, поэтому тоже понадобится спеллмейкерский фреймворк, который просто вернет готовый Spell
|
||||||
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
|
--- @field update fun(self: Spell, caster: Character, dt: number): nil Изменяет состояние спелла
|
||||||
--- @field draw fun(self: Spell): nil Рисует превью каста, ничего не должна изменять в идеальном мире
|
--- @field draw fun(self: Spell): nil Рисует превью каста, ничего не должна изменять в идеальном мире
|
||||||
--- @field cast fun(self: Spell, caster: Character, target: Vec3): nil Вызывается в момент каста, изменяет мир
|
--- @field cast fun(self: Spell, caster: Character, target: Vec3): boolean Вызывается в момент каста, изменяет мир. Возвращает bool в зависимости от того, получилось ли скастовать
|
||||||
local spell = {}
|
local spell = {}
|
||||||
spell.__index = spell
|
spell.__index = spell
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ function spell:update(caster, dt) end
|
|||||||
|
|
||||||
function spell:draw() end
|
function spell:draw() end
|
||||||
|
|
||||||
function spell:cast(caster, target) end
|
function spell:cast(caster, target) return true end
|
||||||
|
|
||||||
local walk = setmetatable({
|
local walk = setmetatable({
|
||||||
--- @type Deque
|
--- @type Deque
|
||||||
@ -18,13 +18,15 @@ local walk = setmetatable({
|
|||||||
|
|
||||||
function walk:cast(caster, target)
|
function walk:cast(caster, target)
|
||||||
local path = self.path
|
local path = self.path
|
||||||
if path:is_empty() then return end
|
if path:is_empty() then return false end
|
||||||
path:pop_front()
|
path:pop_front()
|
||||||
print("Following path: ")
|
|
||||||
for p in path:values() do print(p) end
|
for p in path:values() do print(p) end
|
||||||
caster:has(Tree.behaviors.map):followPath(path)
|
caster:has(Tree.behaviors.map):followPath(path, function()
|
||||||
|
caster:has(Tree.behaviors.spellcaster):endCast()
|
||||||
|
end)
|
||||||
-- TODO: списать деньги за каст (антиутопия какая-то)
|
-- TODO: списать деньги за каст (антиутопия какая-то)
|
||||||
-- TODO: привязка тинькоффа
|
-- TODO: привязка тинькоффа
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function walk:update(caster, dt)
|
function walk:update(caster, dt)
|
||||||
|
|||||||
@ -12,9 +12,16 @@ local SkillButton = ui.Rectangle {
|
|||||||
function SkillButton:update(dt)
|
function SkillButton:update(dt)
|
||||||
ui.Rectangle.update(self, dt)
|
ui.Rectangle.update(self, dt)
|
||||||
self.owner:try(Tree.behaviors.spellcaster, function(spellcaster)
|
self.owner:try(Tree.behaviors.spellcaster, function(spellcaster)
|
||||||
self.color = spellcaster.cast and { 0, 1, 0 } or { 1, 0, 0 }
|
self.color = spellcaster.state == "casting" and { 0, 1, 0 } or { 1, 0, 0 }
|
||||||
self:onTap(function()
|
self:onTap(function()
|
||||||
spellcaster.cast = spellcaster.cast and nil or spellcaster.spellbook[self.spellId]
|
if not spellcaster.cast then
|
||||||
|
spellcaster.cast = spellcaster.spellbook
|
||||||
|
[self.spellId]
|
||||||
|
spellcaster.state = "casting"
|
||||||
|
else
|
||||||
|
spellcaster.state = "idle"
|
||||||
|
spellcaster.cast = nil
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user