Basically, the player in my game is a sprite sheet that gets looped through continuously to make an animation. I know it has something to do with playdate.graphics.animation.loop.new() and maybe playdate.graphics.animation.loop:draw() functions, but I can't figure out how to get a sprite sheet to even display on the screen using these functions, let alone animate continuously. This animation would be on the character sprite that gets moved around with the arrow keys.
Here's my take on this. It's a sprite with a continuous animation. I haven't added controls etc.—let me know if you also need help with that.
import "CoreLibs/sprites"
import "CoreLibs/animation"
-- performance shortcut
local gfx = playdate.graphics
-- Player sprite
local player = gfx.sprite.new()
player:moveTo(100, 100)
-- Let's set the imagetable for the sprite to use
-- it'll be a member of the sprite object for cleanness
player.imagetable = gfx.imagetable.new("Bicycle")
-- this handy SDK function will tell us what frame to draw
-- you just give it the delay betwen frames and what imagetable to use
-- see https://sdk.play.date/#f-graphics.animation.loop.new
player.animation = gfx.animation.loop.new(100, player.imagetable, true)
function player:update()
-- the above animation loop will tell us what frame to use
-- but we still have to tell the sprite TO use it when it updates
self:setImage(self.animation:image())
-- note that the sprite API knows when you've asked it to set the same image again,
-- and it won't update needlessly. This means it will only redraw when really needed
end
player:add()
-- Here we go
function playdate.update()
gfx.sprite.update()
end```
-- Get imagetable from the file and set it to the variable.
local polarbear_spritesheet = gfx.imagetable.new("Minigames/TV_Tuner/images/polar_bear")
-- Create new AnimatedSprite instance using our predefined imagetable.
-- AnimatedSprite is sprite class, that handles animation for itself,
-- no need to invoke update externally.
polarbear = AnimatedSprite.new( polarbear_spritesheet )
-- AnimatedSprite library has build-in finite state machine:
-- You can split your imagetable into states with different settings and switch between them.
-- Here we're creating new state, named "animation"
-- from the first to the last frame of the imagetable (nil, nil).
-- We set tickStep to 3 (Animation will transit to the next image frame every 4 game ticks (if game runs 30 fps then every 100ms).
-- Final "true" is for autoplay.
--
-- You can find all state settings in this wiki:
-- https://github.com/Whitebrim/AnimatedSprite/wiki/Config-parameters
polarbear:addState("animate", nil, nil, {tickStep = 3}, true)
-- Moving sprite to x = 190, y = 120
polarbear:moveTo(190,120)
Thank you all! At this point I'm wondering if there's something going on with my simulator. I've tried Neven's example along with the AnimatedSprite library (which is so straightforward!), but all I can get is the spritesheet to draw to the screen showing all frames, not animated. Here's my current code (basically exactly the same as the examples above).
import "CoreLibs/sprites"
import "CoreLibs/animation"
import "AnimatedSprite.lua"
-- performance shortcut
local gfx = playdate.graphics
-- Player sprite
local player_spritesheet = gfx.imagetable.new("images/Falling-Sheet-table-160-40")
player = AnimatedSprite.new( player_spritesheet )
player:addState("animate", nil, nil, {tickStep = 4}, true)
player:moveTo(190,120)
-- Here we go
function playdate.update()
gfx.sprite.update()
end
I don’t use the AnimatedSprite library myself, but I notice one issue: when defining an imagetable’s path, you should refer just to the part of the filename before the -table. So in your case, images/Falling-Sheet
Thanks! Even when using your code example exactly as it is (except for updating the spritesheet image path, making that line player.imagetable = gfx.imagetable.new("images/Falling-Sheet")) just draws the spritesheet. Here's what my emulator looks like when using your code example:
Yeah, I switched back to your code example and I'm seeing the same result. Here's the code I have, it's the same as yours but with a different image table path. The screenshot I previously posted is the result.
import "CoreLibs/sprites"
import "CoreLibs/animation"
-- performance shortcut
local gfx = playdate.graphics
-- Player sprite
local player = gfx.sprite.new()
player:moveTo(100, 100)
-- Let's set the imagetable for the sprite to use
-- it'll be a member of the sprite object for cleanness
player.imagetable = gfx.imagetable.new("images/Falling-Sheet")
-- this handy SDK function will tell us what frame to draw
-- you just give it the delay betwen frames and what imagetable to use
-- see https://sdk.play.date/#f-graphics.animation.loop.new
player.animation = gfx.animation.loop.new(100, player.imagetable, true)
function player:update()
-- the above animation loop will tell us what frame to use
-- but we still have to tell the sprite TO use it when it updates
self:setImage(self.animation:image())
-- note that the sprite API knows when you've asked it to set the same image again,
-- and it won't update needlessly. This means it will only redraw when really needed
end
player:add()
-- Here we go
function playdate.update()
gfx.sprite.update()
end
Wait! Are your images 40 x 40? The numbers in the imagetable filename should specify the size of one tile, not of the whole image So rename it to -table-40-40. Right now it thinks there’s just one 160 × 40 frame in it.
This filename schema lets you decide on your tile size, and then expand the table size to whatever you need later, as long as it’s a multiple of those numbers.
Your filename there looks odd. In an imagetable filename, the numbers should indicate the size of one tile, which in your case is, I think, 54 × 54. So, rename the file to asteroid-sprites-table-54-54.png.
The reason for this naming is that this way, the compiler knows what size tile to look for. Otherwise, it doesn't know where your tile boundaries are. It also means you can keep enlarging or shrinking your imaginable image without touching your code.