Once an animation is defined from a group of images in the Outline of an Atlas, I can set its FPS to a value I like, however I couldn’t find a documented way to programmatically control sprite sheet animation speed.
I’m thinking about two work-arounds: defining animations with suffixes like run_10fps, run_11fps, run_12fps, etc for different FPS and switching between these animations programmatically - which will most likely cause animation cycle synchronisation issues; alternatively - I can try and create my own sprite sheet animation system on top of Defold and switch the sprites programmatically (one-frame animation per each frame of the cycle).
It’s correct that there is no way to programmatically control the sprite sheet animation speed. All I can think of is doing exactly what you are doing I’m afraid.
I’ve created a ticket for it (DEF-1590). Let’s see if one of the engine guys can provide some feedback.
I’ve needed the same functionality and based on second workaround I’ve prepared simple animation function which does the job using Atlas-based manual animation
First you need to prepare your atlas a bit differently - don’t aggregate your animation frames in animations. Just place the frames in your atlas.
Then use this function:
-- animation [table] - animation description table with following members:
-- * object [string] - url of the sprite which will be animated
-- * time [float] - current time of animation. Elapsed value since start of animaton in seconds. pass 0.0 to start from begining of animation.
-- * duration [float] - animation duration in second. Must be greater than 0.0
-- * time_scale [float] - scalar of animation speed. 1.0 - default speed, 2.0 - double speed, 0.5 - half speed, etc.
-- * frames [table] - a table with animation frames, which are strings of names of your animation frames, e.g. {"frame1", "frame2", "frame3"}
-- * finish_callback - callback function which will be fired when animation finished. May be nil. Will be fired only in case of non-looped animations.
-- dt [float] - time since last frame in seconds.
function update_animation(animation, dt)
if animation.loop == false and animation.time == animation.duration then
return
end
animation.time = animation.time + dt * animation.time_scale
if animation.time > animation.duration then
if animation.loop then
while animation.time > animation.duration do
animation.time = animation.time - animation.duration
end
else
animation.time = animation.duration
end
end
local frames_count = table.getn(animation.frames)
local current_frame = math.min(math.floor((animation.time / animation.duration) * frames_count) + 1, frames_count)
msg.post(animation.object, "play_animation", {id = hash(animation.frames[current_frame])})
if animation.time == animation.duration and not animation.loop and animation.finish_callback ~= nil then
animation.finish_callback()
end
end
You can put the function into a module or use it directly.
The usage is quite simple:
function init(self)
self.idle_animation =
{
object = "#sprite",
time = 0,
duration = 0.4,
time_scale = 1.0,
loop = true,
frames =
{
"frame_0", "frame_1", "frame_2", "frame_3", "frame_4"
},
finish_callback = nil
}
end
function update(self, dt)
update_animation(self.idle_animation, dt)
end