Files
FlexLove/modules/Animation.lua
Michael Freno 712b3c40e9 cleanup
2025-11-13 00:06:09 -05:00

170 lines
4.2 KiB
Lua

--- Easing functions for animations
local Easing = {
linear = function(t)
return t
end,
easeInQuad = function(t)
return t * t
end,
easeOutQuad = function(t)
return t * (2 - t)
end,
easeInOutQuad = function(t)
return t < 0.5 and 2 * t * t or -1 + (4 - 2 * t) * t
end,
easeInCubic = function(t)
return t * t * t
end,
easeOutCubic = function(t)
local t1 = t - 1
return t1 * t1 * t1 + 1
end,
easeInOutCubic = function(t)
return t < 0.5 and 4 * t * t * t or (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
end,
easeInQuart = function(t)
return t * t * t * t
end,
easeOutQuart = function(t)
local t1 = t - 1
return 1 - t1 * t1 * t1 * t1
end,
easeInExpo = function(t)
return t == 0 and 0 or math.pow(2, 10 * (t - 1))
end,
easeOutExpo = function(t)
return t == 1 and 1 or 1 - math.pow(2, -10 * t)
end,
}
---@class Animation
---@field duration number
---@field start {width?:number, height?:number, opacity?:number}
---@field final {width?:number, height?:number, opacity?:number}
---@field elapsed number
---@field transform table?
---@field transition table?
local Animation = {}
Animation.__index = Animation
---@param props AnimationProps
---@return Animation
function Animation.new(props)
local self = setmetatable({}, Animation)
self.duration = props.duration
self.start = props.start
self.final = props.final
self.transform = props.transform
self.transition = props.transition
self.elapsed = 0
-- Set easing function (default to linear)
local easingName = props.easing or "linear"
self.easing = Easing[easingName] or Easing.linear
-- Pre-allocate result table to avoid GC pressure
self._cachedResult = {}
self._resultDirty = true
return self
end
---@param dt number
---@return boolean
function Animation:update(dt)
self.elapsed = self.elapsed + dt
self._resultDirty = true -- Mark cached result as dirty
if self.elapsed >= self.duration then
return true -- finished
else
return false
end
end
---@return table
function Animation:interpolate()
-- Return cached result if not dirty (avoids recalculation)
if not self._resultDirty then
return self._cachedResult
end
local t = math.min(self.elapsed / self.duration, 1)
t = self.easing(t) -- Apply easing function
local result = self._cachedResult -- Reuse existing table
-- Clear previous values
result.width = nil
result.height = nil
result.opacity = nil
-- Handle width and height if present
if self.start.width and self.final.width then
result.width = self.start.width * (1 - t) + self.final.width * t
end
if self.start.height and self.final.height then
result.height = self.start.height * (1 - t) + self.final.height * t
end
-- Handle other properties like opacity
if self.start.opacity and self.final.opacity then
result.opacity = self.start.opacity * (1 - t) + self.final.opacity * t
end
-- Apply transform if present
if self.transform then
for key, value in pairs(self.transform) do
result[key] = value
end
end
self._resultDirty = false -- Mark as clean
return result
end
--- Apply animation to a GUI element
---@param element Element
function Animation:apply(element)
if element.animation then
-- If there's an existing animation, we should probably stop it or replace it
element.animation = self
else
element.animation = self
end
end
--- Create a simple fade animation
---@param duration number
---@param fromOpacity number
---@param toOpacity number
---@return Animation
function Animation.fade(duration, fromOpacity, toOpacity)
return Animation.new({
duration = duration,
start = { opacity = fromOpacity },
final = { opacity = toOpacity },
transform = {},
transition = {},
})
end
--- Create a simple scale animation
---@param duration number
---@param fromScale table{width:number,height:number}
---@param toScale table{width:number,height:number}
---@return Animation
function Animation.scale(duration, fromScale, toScale)
return Animation.new({
duration = duration,
start = { width = fromScale.width, height = fromScale.height },
final = { width = toScale.width, height = toScale.height },
transform = {},
transition = {},
})
end
return Animation