Sprites are all well and good, but if they animate they look so much better. Let’s head towards the end of this project by polishing it a bit.
Part 9: Animation
First up, we need to have some frames of animation for the enemy sprites. To make it a bit more logical on the sprite screen, I’ve moved the first frame from “slot” 2 to “slot” 17, then edited it and created three more frames of animation:
It’s nothing fancy, but you can change that if you like.
Now, when we create the enemy, we need to pass an extra parameter to the make_enemy() function – the total number of animation frames for the sprite. Of course we could hard code this into the enemy object, but lets assume we might want to reuse this function at another time for a range of objects each with a varying number of animation frames.
Currently, the function starts with this:
function make_enemy(espr,ex,ey,ed,eticks,eticksmax)
We’ll add “eframemax” to this:
function make_enemy(espr,ex,ey,ed,eframemax,eticks,eticksmax)
and then set:
en.framemax = eframemax
in the function itself. You’ll see why we had en.frame = 0 in there now!
Next, we need to add some code to change which sprite to use, changing it every so many ticks so it animates like a flickbook. We already have variables for ticks and ticksmax to help with this.
In English, what we need to achieve is this:
- Count up ticks each loop of the game.
- If the ticks hit ticksmax, then change the sprite to the next frame.
- Restart the ticks counter.
- If the sprite frame passes framemax, set it back to the first frame.
- Draw the sprite.
The sprite to draw will be the “base” sprite (i.e. the first sprite of the animation, in this case sprite 17) plus the number of the frame. So 17+0 = 17, then 17+1 = 18, etc. looping back to 17+0. Clear? Great. Here’s the code, which needs to go in the en.draw() function within the make_enemy() function:
en.draw = function(this)
this.ticks += 1 -- increment ticks
if this.ticks == this.ticksmax then
-- have we hit the last tick?
-- if so, inc the frame
if this.frame == this.framemax then
-- have we hit the last frame?
this.frame = 0 -- set back to first frame
else
this.frame += 1 -- inc the frame
end
this.ticks = 0
end
spr(this.sprite+this.frame,this.x,this.y)
end
Note that the spr() code has to change to add the frame number to the sprite number!
One last thing to make this work: You know those two calls to make_enemy()? One in _init() and one in _update()? Well, they both want to create enemies with sprite number 2. It’s 17 now, so we have to change that. Also, we have to include the new framemax parameter.
For the former, change it to:
make_enemy(17,120,120,0.05,3,0,5)
The “3” is the framemax – there are 4 frames numbered 0, 1, 2, 3, remember! The call in _update() needs to change similarly:
make_enemy(17,rnd(128),rnd(128),0.05,3,0,4)
Save it, run it, and watch!
You can play with the “animation speed” using a different final value for ticksmax (the final parameter in the make_enemy() call) instead of 4. Or add more frames, and increase framemax appropriately.
Next time, we’ll look at animating the player too, but until then, here’s all the code so far:
function _init()
-- player start location
x = 64
y = 64
ticks = 0
tickstrigger = 200
dinc = 0.05
-- score
score = 0
-- initialise enemies table
enemies = {}
-- make first enemy
make_enemy(17,120,120,0.05,3,0,5)
end
function _update()
-- check for collision
foreach(enemies, function(en)
if checkcol(x,y,en.x,en.y) then
stop()
end
end)
--[[ check button presses and screen edge
btn(0) is left
btn(1) is right
btn(2) is up
btn(3) is down
]]
if btn(0) and x > 0 then
x -= 1
end
if btn(1) and x < 120 then
x += 1
end
if btn(2) and y > 0 then
y -= 1
end
if btn(3) and y < 120 then
y += 1
end
-- move enemies
foreach(enemies, function(en) en:move() end)
-- increment score
score += 1
-- if ticks are triggered, make enemy faster
ticks += 1
if ticks > tickstrigger then
foreach(enemies, function(en) en.d += dinc end)
ticks = 0
make_enemy(17,rnd(128),rnd(128),0.05,3,0,4)
end
end
function _draw()
cls(2) -- clear the screen to mauve
print(score,100,0,7) -- print score
spr(1,x,y) -- draw sprite 1 at x, y
-- draw all enemies
foreach(enemies, function(en) en:draw() end)
end
function checkcol(ax,ay,bx,by)
if bx+8>ax and bx<ax+8 and by+8>ay and by<ay+8 then
return true
else
return false
end
end
function make_enemy(espr,ex,ey,ed,eframemax,eticks,eticksmax)
en = {}
en.sprite = espr
en.x = ex
en.y = ey
en.d = ed
en.frame = 0
en.framemax = eframemax
en.ticks = eticks
en.ticksmax = eticksmax
en.draw = function(this)
this.ticks += 1 -- increment ticks
if this.ticks == this.ticksmax then
-- have we hit the last tick?
-- if so, inc the frame
if this.frame == this.framemax then
-- have we hit the last frame?
this.frame = 0 -- set back to first frame
else
this.frame += 1 -- inc the frame
end
this.ticks = 0
end
spr(this.sprite+this.frame,this.x,this.y)
end
en.move = function(this)
if x < this.x then this.x -= this.d end
if x > this.x then this.x += this.d end
if y < this.y then this.y -= this.d end
if y > this.y then this.y += this.d end
end
add(enemies,en)
end

