143 lines
4.9 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local easing_lib = require "lib.utils.easing"
local lerp = require "lib.utils.utils".lerp
--- Обобщенная асинхронная функция (Task).
--- По сути это функция, принимающая коллбэк: `fun(callback: fun(value: T): nil): nil`
--- @generic T
--- @alias Task fun(callback: fun(value: T): nil): nil
local task = {}
local activeTweens = {} -- list of tweens
-- We also need a way to track tweens by target to support cancellation/replacement
-- Let's stick to a simple list for update, but maybe add a helper to find by target?
-- Or, just allow multiple tweens per target (which is valid for different properties).
-- But if we animate the SAME property, we have a conflict.
-- For now, let's just add task.cancel(target) which kills ALL tweens for that target.
--- Обновление всех активных анимаций (твинов).
--- Нужно вызывать в love.update(dt)
function task.update(dt)
for i = #activeTweens, 1, -1 do
local t = activeTweens[i]
if not t.cancelled then
t.elapsed = t.elapsed + dt * 1000
local progress = math.min(t.elapsed / t.duration, 1)
local value = t.easing(progress)
for key, targetValue in pairs(t.properties) do
t.target[key] = lerp(t.initial[key], targetValue, value)
end
if progress >= 1 then
t.completed = true
table.remove(activeTweens, i)
if t.resolve then t.resolve() end
end
else
table.remove(activeTweens, i)
end
end
end
--- Возвращает Completer — объект, который позволяет вручную завершить таску.
--- @generic T
--- @return { complete: fun(val: T) }, Task<T> future
function task.completer()
local c = { completed = false, value = nil, cb = nil }
function c:complete(val)
if self.completed then return end
self.completed = true
self.value = val
if self.cb then self.cb(val) end
end
local future = function(callback)
if c.completed then
callback(c.value)
else
c.cb = callback
end
end
return c, future
end
--- Отменяет все активные твины для указанного объекта.
--- @param target table
function task.cancel(target)
for _, t in ipairs(activeTweens) do
if t.target == target then
t.cancelled = true
end
end
end
--- Создает таску, которая плавно меняет свойства объекта.
--- Автоматически отменяет предыдущие твины для этого объекта (чтобы не было конфликтов).
--- @param target table Объект, свойства которого меняем
--- @param properties table Набор конечных значений { key = value }
--- @param duration number Длительность в мс
--- @param easing function? Функция смягчения (по умолчанию linear)
--- @return Task<nil>
function task.tween(target, properties, duration, easing)
task.cancel(target) -- Cancel previous animations on this target
local initial = {}
for k, _ in pairs(properties) do
initial[k] = target[k]
if type(initial[k]) == "table" and initial[k].copy then
initial[k] = initial[k]:copy() -- Для Vec3
end
end
local comp, future = task.completer()
table.insert(activeTweens, {
target = target,
initial = initial,
properties = properties,
duration = duration or 1000,
easing = easing or easing_lib.linear,
elapsed = 0,
resolve = function() comp:complete() end
})
return future
end
--- Возвращает таску, которая завершится сразу с переданным значением.
function task.fromValue(val)
return function(callback) callback(val) end
end
--- Возвращает новый Task, который завершится после завершения всех переданных `tasks`.
--- @param tasks Task[]
--- @return Task<any[]>
function task.wait(tasks)
if #tasks == 0 then return task.fromValue({}) end
local count = #tasks
local results = {}
return function(callback)
for i, t in ipairs(tasks) do
t(function(result)
results[i] = result
count = count - 1
if count == 0 then callback(results) end
end)
end
end
end
--- Последовательно объединяет два `Task` в один.
--- @param t Task
--- @param onCompleted fun(value: any): Task
--- @return Task
function task.chain(t, onCompleted)
return function(callback)
t(function(value)
local t2 = onCompleted(value)
t2(callback)
end)
end
end
return task