185 lines
5.3 KiB
Lua
185 lines
5.3 KiB
Lua
require "api.logging"
|
|
|
|
require "common.class"
|
|
|
|
require "api.filesys"
|
|
|
|
require "api.graphics"
|
|
|
|
local Image = require "api.image"
|
|
|
|
---@class AnimationParam: Animation
|
|
---@field animPath string
|
|
---@field animFPS number
|
|
|
|
---@class Animation
|
|
---@field frames Image[]
|
|
---@field frameCount integer
|
|
---@field frameTime number
|
|
---@field loop boolean
|
|
---@field loopPoint integer
|
|
---@field width number?
|
|
---@field height number?
|
|
---@field x number?
|
|
---@field y number?
|
|
---@field scaleX number?
|
|
---@field scaleY number?
|
|
---@field centered boolean?
|
|
---@field blendOp integer?
|
|
---@field color number[]?
|
|
---@field alpha number?
|
|
---@field stroke StrokeParams?
|
|
local Animation = { }
|
|
|
|
---@class AnimationState
|
|
---@field animation Animation # The animation data this state is playing through
|
|
---@field frameIndex integer # Current frame in the animation
|
|
---@field timer number # Timer used to determine when to change to the next frame
|
|
---@field running boolean # Is the animation currently running and accepting updates?
|
|
---@field callback function? # Called when the animation completes
|
|
local AnimationState = { }
|
|
|
|
---Load Animation Frames from path
|
|
---@param animPath string
|
|
---@return Image[]
|
|
---@return integer
|
|
local function loadSequentialAnimationFrames(animPath)
|
|
local frames = { } ---@type Image[]
|
|
local count = 0
|
|
|
|
local anim_files = filesys.scandir(filesys.fromTexturePath(animPath))
|
|
|
|
for index, frame_path in ipairs(anim_files) do
|
|
frame_path = filesys.join(filesys.normpath(animPath), frame_path)
|
|
DetailedLog("Frame "..index..": '"..frame_path.."'", game.LOGGER_DEBUG)
|
|
local frame = Image.new(frame_path, true)
|
|
|
|
if not frame then
|
|
DetailedLog("Could not load frame image '"..frame_path.."'", game.LOGGER_ERROR)
|
|
break
|
|
end
|
|
|
|
frames[index] = frame
|
|
count = count + 1
|
|
end
|
|
|
|
|
|
return frames, count
|
|
end
|
|
|
|
---Animation constructor
|
|
---@param params AnimationParam
|
|
---@return Animation
|
|
function Animation.new(params)
|
|
local self = CreateInstance(Animation, params)
|
|
|
|
self.frames, self.frameCount = loadSequentialAnimationFrames(params.animPath)
|
|
|
|
self.frameTime = 1 / (params.animFPS or 30)
|
|
self.loop = params.loop or false
|
|
self.loopPoint = params.loopPoint or 1
|
|
|
|
self.width = params.width
|
|
self.height = params.height
|
|
self.x = params.x
|
|
self.y = params.y
|
|
self.scaleX = params.scaleX
|
|
self.scaleY = params.scaleY
|
|
self.centered = params.centered
|
|
self.blendOp = params.blendOp
|
|
self.color = params.color
|
|
self.alpha = params.alpha
|
|
self.stroke = params.stroke
|
|
|
|
return self
|
|
end
|
|
|
|
---Create an AnimationState to play this animation.
|
|
---The AnimationState is not started.
|
|
---@param callback function?
|
|
---@return AnimationState
|
|
function Animation:createState(callback)
|
|
---@type AnimationState
|
|
local state = { animation = self, callback = callback, frameIndex = 1, timer = 0, running = false }
|
|
return CreateInstance(AnimationState, state)
|
|
end
|
|
|
|
---Create an AnimationState to play this animation and start it.
|
|
---@param callback function?
|
|
---@return AnimationState
|
|
function Animation:start(callback)
|
|
local state = self:createState(callback)
|
|
state:start()
|
|
|
|
return state
|
|
end
|
|
|
|
---Start this AnimationState.
|
|
---Does nothing if it's already running.
|
|
function AnimationState:start()
|
|
self.running = true
|
|
end
|
|
|
|
---Restart this AnimationState.
|
|
---The frame index is reset to 1.
|
|
function AnimationState:restart()
|
|
self.running = true
|
|
self.frameIndex = 1
|
|
self.timer = 0
|
|
end
|
|
|
|
---Stop this AnimationState.
|
|
function AnimationState:stop()
|
|
self.running = false
|
|
end
|
|
|
|
---Updates this AnimationState and then renders it, passing on the given ImageParams to each frame.
|
|
---@param deltaTime number
|
|
---@param params? ImageParams
|
|
function AnimationState:render(deltaTime, params)
|
|
if (not self.running) then return end
|
|
|
|
self.timer = self.timer + deltaTime
|
|
|
|
while (self.timer > self.animation.frameTime) do
|
|
self.timer = self.timer - self.animation.frameTime
|
|
self.frameIndex = self.frameIndex + 1
|
|
|
|
if (self.frameIndex > self.animation.frameCount) then
|
|
if (self.animation.loop) then
|
|
self.frameIndex = self.animation.loopPoint
|
|
else
|
|
self.running = false
|
|
|
|
if (self.callback) then
|
|
self.callback()
|
|
end
|
|
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
if (params) then
|
|
if (params.width == nil) then params.width = self.animation.width end
|
|
if (params.height == nil) then params.height = self.animation.height end
|
|
if (params.x == nil) then params.x = self.animation.x end
|
|
if (params.y == nil) then params.y = self.animation.y end
|
|
if (params.scaleX == nil) then params.scaleX = self.animation.scaleX end
|
|
if (params.scaleY == nil) then params.scaleY = self.animation.scaleY end
|
|
if (params.centered == nil) then params.centered = self.animation.centered end
|
|
if (params.blendOp == nil) then params.blendOp = self.animation.blendOp end
|
|
if (params.alpha == nil) then params.alpha = self.animation.alpha end
|
|
if (params.stroke == nil) then params.stroke = self.animation.stroke end
|
|
end
|
|
|
|
local frame = self.animation.frames[self.frameIndex]
|
|
if (not frame) then
|
|
-- TODO(local): what do
|
|
else
|
|
frame:render(params)
|
|
end
|
|
end
|
|
|
|
return Animation
|