renamed module directory
This commit is contained in:
188
modules/Animation.lua
Normal file
188
modules/Animation.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
---@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?
|
||||
--- 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,
|
||||
}
|
||||
|
||||
local Animation = {}
|
||||
Animation.__index = Animation
|
||||
|
||||
---@class AnimationProps
|
||||
---@field duration number
|
||||
---@field start {width?:number, height?:number, opacity?:number}
|
||||
---@field final {width?:number, height?:number, opacity?:number}
|
||||
---@field transform table?
|
||||
---@field transition table?
|
||||
local AnimationProps = {}
|
||||
|
||||
---@class TransformProps
|
||||
---@field scale {x?:number, y?:number}?
|
||||
---@field rotate number?
|
||||
---@field translate {x?:number, y?:number}?
|
||||
---@field skew {x?:number, y?:number}?
|
||||
|
||||
---@class TransitionProps
|
||||
---@field duration number?
|
||||
---@field easing string?
|
||||
|
||||
---@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
|
||||
Reference in New Issue
Block a user