232. Angry Birds – Animated pigs
In this post, I import a spritesheet and break it up into animations for the different types of pig, as shown below (you may need to make it fullscreen to see the pigs at the bottom properly, or better, run the code at the end of the post).
Finding images
The first problem is to find some images for Angry Birds. Fortunately, some kind person has done all the work for us, including all the images we’ll need for an animation. Here is the sheet of images that I found (we don’t have a problem with copyright, as long as we’re just doing this for fun and not sharing it).
This is known as a spritesheet, and is the best way to import lots of images into an app, simply because your app only has to read one image from disk. Of course, then we need to break up the sheet into individual images, which we do in code.
At this stage, you should save this image to your Codea dropbox account (as AngryBirds.png), and then sync it in Codea, so it will show up in our app.
Pigs
I started by looking at the pigs. There are 6 sets of images, which I’ve called”king”,”mustache”,”medium”,”small”,”tiny”,and “helmet”. Each set has 9 images (you may have to look around the sheet to find them) – 3 undamaged pigs, 3 with one eye closed, and 3 with both eyes closed. The idea is to animate the pigs by rotating through whichever set of 3 images applies (depending on how damaged the pig is).
I need to think about how to store these images in a way that makes it easy to switch between the image sets, and to play back the animations.
I also have to extract all the individual images from the spritesheet, which is a slow and careful process.
Extracting images
I loaded the image into a paint program (I use paint.net, but any program will do, if it gives you pixel positions as you move your mouse around). I wrote down all the measurements and then wrote code to read it in.
Storing the images
I’ve stored all the images in a table called images. Each pig has its own set of 9 images, which are saved as a table, made up of three further tables, each with 9 images. The easiest way to understand this by looking at code. Below is the first part, that reads in the king pig. See the numbered notes underneath.
img=readImage("Dropbox:AngryBirds") images={} local p={} --[1] --read king pig images for i=1,6 do p[i]=img:copy(math.floor(1+(i-1)*62.5),354,63,69) end --[2] for i=1,3 do p[i+6]=img:copy(0,349-i*69,63,71) end --[3] images["king"]={{p[1],p[2],p[3]},{p[4],p[5],p[6]},{p[7],p[8],p[9]}} --[4]
I have a problem, which is that although many of the images are in rows, they are in the wrong order. I’d like to read rows of images in using a loop rather than one at a time, but then I would have to re-order them.
So what I’ve done is to read all 9 images (for one of the pigs) into a table called p, in any order, then I create my final table in the right order.
[1] I create a table p to hold the images, as I pull them out of the spritesheet
[2] and [3] I use loops and the copy command to copy parts of the image into the p table. (Note that I use math.floor in one place because the gap between images is 62.5, but the copy command only accepts integers).
[4] Now I put them into the images table under the name “king”, as a set of three tables (one for each damage state), each with the images that will rotate to animate the pig. The king pig is easy because all the images were in the right order, but most of the others are out of order.
Testing the results
I wrote the code for each pig, one at a time, and animated them to make sure they looked OK. I had to make lots of little adjustments to get it right, but finally, I think all 6 pigs have their 3 different animations working. The video at top shows the spritesheet in the middle of the screen, and the 6 pigs are animated underneath. I have a parameter which I use to change the damage state to one eye closed, and then both eyes closed, so the video shows all the animations.
Note that the animations don’t change every frame – that would be much too fast. I’ve set a delay of 0.5 seconds.
So here is (most of) my test program, excluding the part that reads in all the images. The first part is pretty easy to follow.
function setup() Settings() LoadImages() CreatePigs() parameter.integer("Damage",1,3,3) end function Settings() animDelay=1 --seconds between animation changes end function draw() background(132, 185, 203, 255) sprite(img,WIDTH/2,HEIGHT/2) DrawPigs() end
Creating the pigs is easy, too. I created a function ResetCounter, so that every time a pig goes from one damage state to another, the animations start from the first image again, and the time until the next animation change is reset, too. I added a random amount, so that the pigs animate at different times and are not synchronised.
The DrawPigs function is pretty simple, too. As well as drawing the pigs, it checks whether it is time to move to the next image.
function CreatePigs() pigTypes={"king","mustache","medium","small","tiny","helmet"} pigs={} for i=1,#pigTypes do pigs[i]={} pigs[i].type=pigTypes[i] pigs[i].state=1 --damage state, 1-3 ResetCounter(pigs[i]) end end function ResetCounter(p) p.img=1 --reset to first image p.nextAnim=ElapsedTime+animDelay-math.random()*0.5 end function DrawPigs() for i,p in pairs(pigs) do local j=images[p.type][Damage] sprite(j[p.img],50+100*i,100) if ElapsedTime>p.nextAnim then p.img=p.img+1 if p.img>#j then p.img=1 end p.nextAnim=ElapsedTime+animDelay end end end
Birds
The birds are more complicated. I think I’m just going to pull out the red bird, which is the simplest, and get the game working with him, before I try the others.
Code
The full code is here.