Does Codea support sprite sheets?

From what I know sprite sheets save memory used or so I’ve heard. Wouldn’t adding sprite sheet support be beneficial? How do you animate something in codea without a sprite sheet? Is it just redrawing the scene and the sprite being a different image in the animation?

today it’s roll-your-own , or dig through the forums and find someone else’s.

Try using meshes, and setting the texture coordinates…

That’s a good idea. Someone make a sprite sheet demo. I’m still trying to understand all these matrices and viewports.

Sprite sheets in codea don’t save any memory.
Codea uses a texture atlas for all textures (works just like a sprite sheet), but the issue some people face is speed. The idea being that managing your own sprite sheet will be faster than the inbuilt lookup of the entire texture atlas.
But I have to say just calling each ‘image’ to draw for each frame is fast enough in my experience.

Here’s a demo of an animation from a sprite sheet using meshes. You probably want to ship out the sprite handling to a separate class, but this is just to demo the concept.
You can get the sprite sheet here (hopefully!)
http://db.tt/eMJa1tsS


-- ZombieAnimationDemo
-- by West

-- Use this function to perform your initial setup
function setup()
    
--load up the sprite sheet into a mesh
-- in this case the sprite sheet contains 5 by 5 sprites, each 32 by 32 pixels
-- the file is available from
--http://db.tt/eMJa1tsS
zombie=mesh()
-- you may need to change this to the location where you save the file
img=readImage("Dropbox:ZombieSpriteSheet")
zombie.texture=img
rows=5 --number of rows in the sprite sheet
cols=5 -- number of columns in the sprite sheet
sizex=64 -- width of the sprite image to display on screen - note this does not need to be the original pixel size
sizey=64 -- height of the sprite image
--set up some constants
walkleft=0
walkright=1
turnlefttoright=2
turnrighttoleft=3

--set up some arrays to hold the animations
animdelay=0
animdelaymax=3
animx={}
animy={}
movex={}
movey={}
--define the animation frames
--starting from bottom left as 0,0, enter the column (animx) and row (animy) of the frame you want
--walking left
animx[0]={0,1,2,3,4,0,1,2} 
animy[0]={4,4,4,4,4,3,3,3}
movex[0]={-1,-1,-1,-1,-1,-1,-1,-1}
movey[0]={0,0,0,0,0,0,0,0}
--walking right
animx[1]={0,1,2,3,4,0,1,2}
animy[1]={2,2,2,2,2,1,1,1}
movex[1]={1,1,1,1,1,1,1,1}
movey[1]={0,0,0,0,0,0,0,0}
--turning left to right
animx[2]={3,4,3}
animy[2]={3,3,1}
movex[2]={0,0,0}
movey[2]={0,0,0}
--turning right to left
animx[3]={3,4,3}
animy[3]={1,3,3}
movex[3]={0,0,0}
movey[3]={0,0,0}

x=150  --initial  x coordinate of the sprite
y=HEIGHT/2  -- initial y coordinate of the sprite
state=walkleft -- initial state of the sprite
curFrame=1 -- the initial frame of the animation in terms of the position in the animx and animy arrays
speed=3 -- a factor by which to speed up the movement (alternatively change the values in movex but this provides greater flexibilty
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    --clear the mesh
    zombie:clear()


--cycle through the animation
--add a delay to solw the animation down
animdelay = animdelay + 1
if animdelay>animdelaymax then
    --move to the next frame in the animation
    curFrame = curFrame + 1
    --check to see if this frame is past the end of the animation array for the current state and if so, reset
    if curFrame>#animx[state] and state==turnlefttoright then
        state=walkright
        curFrame=1
    elseif curFrame>#animx[state] and state==turnrighttoleft then
        state=walkleft
        curFrame=1
    elseif curFrame>#animx[state] then
        curFrame=1
    end

    --reset the animation delay counter
    animdelay=0
end
    --adjust the position according to the values in the movement arrays
    x = x + movex[state][curFrame]*speed
    y = y + movey[state][curFrame]*speed -- not needed in this demo as there is no vertical movement
--check to see if the edges of the screen have been met
if x>WIDTH-100 and state~=turnrighttoleft then
    state=turnrighttoleft
    curFrame=1 -- reset the animation
elseif x<100 and state~=turnlefttoright then
    state=turnlefttoright
    curFrame=1
end
    -- Do your drawing here
     local idx=zombie:addRect(x,y,sizex,sizey)
    zombie:setRectTex(idx,(animx[state][curFrame])/cols,(animy[state][curFrame])/rows,1/cols,1/rows)   
    
    --draw the mesh
    zombie:draw()
end

Could’t get the sheet, though i tried from my ipad and i wasn’t logged in. Your public link does not go to your account.

Hmmm not sure how to post the link then

Ok this should now work. Have edited the original post above too

http://db.tt/eMJa1tsS

I could copy and paste it on my ipad. Thank you for the really helpfull example.

Hi all,

I tried this sample and it works fine but I get some artifacts at the top and bottom of the animated sprite in the form of a thin horizontal line. It’s not that noticeable with the Zombie example since the colours are dark, but when I tried it with a more colourful image it was more noticeable.

Has anyone got an idea why it might be happening?

Paul.

If your running on a retina device then it might be due to the texture bleeding in from the edges. This is a common problem on a lot of high resolution graphic devices and the reason why texturepacker and similar tools allow for a degree of padding between elements - try shifting your texture u.v coords in by half a pixel

Yes, i’m running on iPad Air 1. You’re also correct that my sprite sheet doesn’t have any padding between elements. I’ll try and fix that first in the sprite sheet image.

Many thanks!

@osullivp You could also try noSmooth() to disable the smoothing that causes bleeding, but your graphics will be pixelated (I would assume that would be fine, people don’t typically use high-res spritesheets).

Here’s a version saving each image in a table. Tap the screen to move thru the images. It’s possible the artifacts in the other code is caused by capturing some of the image above or below the current image.


displayMode(FULLSCREEN)

function setup()
    i=1
    spriteMode(CORNER)
    img1=readImage("Dropbox:ZombieSpriteSheet")    
    img2=image(80,80)    
    setContext(img2)
    sprite(img1,0,0)
    setContext()

    tab={}
    count=0
    for y=64,1,-16 do
        for x=1,64,16 do
            count=count+1
            if count<20 then
                table.insert(tab,img2:copy(x,y,16,16))
            end
        end
    end
end

function draw()
    background(40,40,50)
    sprite(img1,50,200,200)
    sprite(tab[i],350,200,200)
end

function touched(t)
    if t.state==BEGAN then
        i=i+1
        if i>#tab then
            i=1
        end
    end
end

@dave1707 there’s something wrong with your code. the tab[i] rendering looks terrible, and isn’t extracting properly from the original sprite sheet. can you post a screen shot of what yours is supposed to look like when working properly?

@matkatmusic What is the size of the ZombieSpriteSheet that’s in your Dropbox. It should have a size of 80 x 80 . That’s what this code is set up for. If it still doesn’t work, maybe I’ll change the code to read the sheet from the link given above.

@matkatmusic As for what it’s supposed to look like, the whole sprite sheet will be on the left of the screen and an individual character the same size of the sprite sheet will be on the right. Each time you tap the screen, the next character in the sprite sheet will be shown.

i see that, it’s just way zoomed in on the right. like, i see a partial view of the dude’s legs.

I fixed it. the spritesheet was 160x160

function setup()
    i=1
    spriteMode(CORNER)
    img1=readImage("Dropbox:ZombieSpriteSheet")    
    img2=image( spriteSize(img1)  )    
    setContext(img2)
    sprite(img1,0,0)
    setContext()
    print( spriteSize( img1 ) )
    w,h = spriteSize( img1 ) 
    tab={}
    count=0
    for y=128,1,-32 do
        for x=1,128,32 do
            count=count+1
            if count<20 then
                print( x, y, w/5, h/5 )
                table.insert(tab,img2:copy(x,y,w/5,h/5))
            end
        end
    end
    
    counter = 1
    fr = 0
end

function draw()
    background(40,40,50)
    sprite(img1,50,200 )
    sprite(tab[counter],350,200)
    fr = fr + 1
    if( fr > 3 ) then 
        fr = 0
        counter = counter + 1
        if( counter > #tab ) then counter = 1 end
    end
end

the sprite sheet in question was one of those dropbox links above. not sure which one. it’s whichever one was 160x160