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