Fortunately not, thanks to player tiles supporting transparency. I'll try my best to briefly explain my approach (and maybe I'm missing a trick to simplify the animation!).
First I have a few variables keeping track of the player's position and direction, which is useful for checking when the player's position has changed and for making sure the player tile matches the direction.
Originally I was updating these at the end of the player's update
event like:
posx = event.px
posy = event.py
pdx = event.dx
pdy = event.dy
However that was causing a minor bug as it turns out update
is called before the player is moved when stepping onto an exit - event.px
, event.py
and event.room
will all report the player's position when stepping onto the exit, not after being moved by the exit. I moved the position tracking to the end of the player's draw
event instead to fix this (the direction tracking stayed in update
as it is more limited in which events it is available).
Anyway, the reason that is useful is because during the update
event I check if the player's position has changed by comparing my tracked variables and what is reported by event.px
and event.py
. If they are different I set a variable called player_moving_frame
to 1
and call ignore
. The variable flags that the game should animate movement (and I also use it to know what animation frame to use each game frame - more on that later) while the ignore
is just to prevent any more input until the movement animation is complete.
I want my player to be animated at 2 fps, but because I'm going to be drawing some player tiles directly to the screen as frames I can't just rely on Pulp's fps config - I need to manually sync the animation myself. So in the game's loop
event I have a generic counter that restarts every 20 frames (1 second):
counter20++
if counter20==20 then
counter20 = 0
end
Then at the start of my player draw
event I have:
if counter20<10 then
player_frame = 0
else
player_frame = 1
end
Then I have my animation handling inside a conditional on player_moving_frame>=0
.
Here comes the fiddly bit - the player tiles.
To smoothly animate I need to have 2 tiles animating together, one for the player "entering" at their new position and one for "exiting" their old position.
"Enter" is the easier half. As it's the actual player tile, I can swap it and then set the frame like this:
swap "player enter {pdx}{pdy} {player_frame}"
frame player_moving_frame
I have animated tiles set to 0 fps for all four directions and for both animation states. Those tiles have 7 frames each moving the player 1 pixel at a time further into the tile, the rest is transparency.
"Exiting" is more difficult, because rather than swapping the player tile I have to draw the exiting animation to the player's previous position. As far as I can tell, you can't specify a frame when drawing a tile. This means that instead of 8 tiles with 7 frames of animation each, I have 56 player tiles each with a single frame. I then choose exactly which tile to draw like so:
draw "player exit {pdx}{pdy} {player_frame} {player_moving_frame}" at x,y
Fear not - I don't actually end up using most of those tiles! Having them all lets you smoothly animate movement 1 pixel at a time. At 20 fps this felt too slow, so I ended up incrementing player_moving_frame
by 2 every frame. Like this:
player_moving_frame += 2
if player_moving_frame>6 then
player_moving_frame = -1
listen
end
So for my animation I only actually go through frames 1, 3 and 5.
There were a few other fixes I had to do but that's the crux of it. I'll see if I can just cut out that code specifically and share the json so you can take a look, if you're interested!