Animated Sprite helpful class

You're right, I might copy-paste similar configs for new animations and just tweak some parameters, then compile to see how it's doing...

1 Like

:exclamation: There was "pdxinfo is missing" problem with playdate sideload feature caused by this lib.
I've fixed that, I highly recommend updating from git repo or not adding test/ folder into your game.

First off, thanks for making such an incredible resource. I'm not sure if I'm thinking about it wrong, but I'm having a hard time figuring out how to use it to draw multiple instances of the same animation.

For example, in my game there are items scattered randomly around the level. Previously, I implemented this using the built-in Playdate animation loops, something like (using pseudocode)

if tile is onscreen then
   if tile.item ~= nil then
      draw tile.item at tile.position

I was planning on doing something similar with AnimatedSprite, however I don't see a way to not draw an AnimatedSprite once it's been created. My concern is I don't want to draw the animations when they're not on screen (since you mentioned there are performance concerns and I may have hundreds of items on the map). I suppose I could play and pause the animations when they enter/exit the screen, but would there still be a performance hit even if the animation is paused? Or is there a way of doing this that I'm missing?

1 Like

This is new use case for me, I didn't think about it before. For my endless runner game I just create new instance of the AnimatedSprite and delete it when it's out of the screen...

You can override default :update() function to empty function (don't call :updateAnimation()), you need to call :updateAnimation() manually then. + Maybe removing AnimatedSprite(32 line): self:add() will help with performance, but you need to call:updateAnimation() every frame (idk if it'll work)~

Mind if I ask how you delete it? I think that could work for my case as well.

Edit: Actually I think I see, you just add and delete from the list of sprites. But is there a good way to add the same Animated Sprite multiple times at different positions?

By delete I mean open AnimatedSprite.lua file and delete code) You can create copy of the original class and have AnimatedSprite.lua and AnimatedStaticSprite.lua (without automatic :add()). For normal animations use AnimatedSprite that will automatically animate and for your tile animations you can use AnimatedStaticSprite and invoke :updateAnimation() manually.

But is there a good way to add the same Animated Sprite multiple times at different positions?

I don't know what you're talking concterly, but you can use for cycle to create multiple sprites...

Thanks @Whitebrim for this library, I have an issue while using it

main.lua

function playdate.update()

    gfx.sprite.update()
    playdate.timer.updateTimers()

end

but this update is not calling the update function in the player.lua , as I can't able to move my sprite

class("Player").extends(AnimatedSprite)

function Player:init(x, y)
    imgtable = pd.graphics.imagetable.new("Images/flight-table-24-24")
    playerSprite = AnimatedSprite.new(imgtable)   -- creating animated sprite
    playerSprite:addState('idle', 1, 2, {tickStep = 2})
    playerSprite:playAnimation()
    playerSprite:setCollideRect(0, 0, playerSprite:getImage(1):getSize())

    playerSprite:moveTo(x, y)
    playerSprite:add()
end

function Player:update()
    print("update called ...")
    if pd.buttonIsPressed( pd.kButtonUp ) then 
        playerSprite:moveBy( 0, -2 )
    end
    if pd.buttonIsPressed( pd.kButtonRight ) then
        playerSprite:moveBy( 2, 0 )
    end
    if pd.buttonIsPressed( pd.kButtonDown ) then
        playerSprite:moveBy( 0, 2 )
    end
    if pd.buttonIsPressed( pd.kButtonLeft ) then
        playerSprite:moveBy( -2, 0 )
    end
end

As the class AnimatedSprite is extending sprites, I thought this will work, but its not getting called, any ideas ?

(edited : 26Jul)

Hi, @jae, here's:

Wiki

Update override case

You don't need to call playerSprite:add()

Timers aren't used in AnimatedSprite, if you don't use them too, you can remove playdate.timer.updateTimers() too.

I assume Player is not animated sprite class, Player:update() is not handled by this lib, if it was playerSprite:update() instead, then it will be handled by gfx.sprite.update() because playerSprite is sprite. I'm not sure if Player is sprite, therefore nobody invokes Player:update(). Your problem was that "update called ..." never appears in the logs, right?

Thanks @Whitebrim for your quick answer , I missed the vital part of the code where the Player class is extending AnimatedSprite class.

Thanks to your answer , I figured out I need to use (updated code)

function AnimatedSprite:update()
    print("update is called")
    if pd.buttonIsPressed( pd.kButtonUp )  then
        playerSprite:moveBy( 0, -2 )
    end
    .
    .
    .
end

And now the update function is called.

Also, are there any examples available to use collision along with the AnimatedSprite component ?

Here's my code from cranner that uses collisions (groups):
link

Hi! I'm new to Lua, and game development in general, so forgive me if there are silly questions.

Global flip will flip symmetrical sprites to face left or right, but what is the best practice for asymmetrical sprites?
I have animations in the sprite sheet for each facing. Would you make a state for each direction and use input handling to determine which state to use?

Would using a json configuration be better than the basic initialization if the sprite has a lot of animations and transitions between them?

I suggest using json for faster initialization and for you to better understand what is happening in your states.

If you can't achieve desired turning via flipX and flipY, the only way is to use different states for different directions. I suggest creating states withthe same number of frames and using :getCurrentFrameLocalIndex() and :changeStateAndSelectFrame(name, frameIndex, [play]) to save animation flow.
You copy current state local frame index and apply this index to the next state.
This indexes should have the same animation moment if you set up all correctly.

Also, can you please show sprite that you name asymmetrical?

1 Like

Thanks for such a quick response!

By save animation flow, do you mean to have a smooth transitions between states like "jump"=>"fall"=>"land"?

It's a large sprite sheet so I just cut out his run cycle as an example, but as you can see: When he's facing right his sheriff badge and gun/holster can be seen, but facing left just his tactical pocket on the other side.

1 Like

Yeah, you need to use different states here, flip can't do.
By saving animation flow I mean when he rises his leg, if changed to different rotation animation state, he will be still lifting his leg.

1 Like

hero:changeStateAndSelectFrame(newStateName, hero:getCurrentFrameLocalIndex())
Where hero is name of hero class and newStateName is left or right state name.