Animation logic using anim8

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
tehryanx
Prole
Posts: 17
Joined: Fri Apr 04, 2014 8:26 pm

Animation logic using anim8

Post by tehryanx »

I'm using anim8 to handle animations for a platformer. I'm finding myself at a roadblock with some animations and I'm not sure how to proceed.

The way my animations are set up currently is in a table like so:

Code: Select all

	player.animations['walk'] = anim8.newAnimation(grid('1-8',1), 0.1)
	player.animations['idle'] = anim8.newAnimation(grid('1-8',2), 0.1)
	player.animations['longidle'] = anim8.newAnimation(grid('1-8',3), 0.1)
	player.animations['climb'] = anim8.newAnimation(grid('1-8',4), 0.1)
	player.animations['jump'] = anim8.newAnimation(grid('1-8',5), 0.1)
	player.animations['duck'] = anim8.newAnimation(grid('1-8',6), 0.1)
	player.animations['attack'] = anim8.newAnimation(grid('1-7',7), 0.1)
	player.animations.current = player.animations['idle']
...

and the current animation is set based on the players state like so:

Code: Select all

function player.setState(state)
	if player.animations.current ~= player.animations[state] then
		player.animations.current = player.animations[state]
	end
	player.state = state
end
My problem is that, for some animations, I want the animation to always start on the first frame, and I want it to finish the entire animation before allowing the player to change his state.

So for example, the attack animation is 7 frames long. When I press the attack key, I want to set the players state to attack, which will begin playing the attack animation. I want this animation to play one time the entire way through and stop at the end no matter when the player lets go of hte attack key. Meaning, if he taps the key the animation plays one time through, or if he holds the key down forever the animation still plays only one time through.

I know there's a "pauseAtEnd" function in anim8, but as soon as I lift my finger off the key my player.state reverts to idle, which changes the animation before it's finished playing.

I'm looking for a solution that will easily cover any additional animations I decide to add. Is there an article anywhere that explains handling this kind of animation? Or if it's just something simple I'm missing could someone here offer any advice? Thanks!
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Animation logic using anim8

Post by kikito »

I want the animation to always start on the first frame
That can be done like this:

Code: Select all

function player.setState(state)
   if player.animations.current ~= player.animations[state] then
      player.animations.current = player.animations[state]
      player.animations.current:gotoFrame(1)
   end
   player.state = state
end
and I want it to finish the entire animation before allowing the player to change his state.
That is not anim8's job. "I should not be able to cancel a shooting animation by moving" is not an animation's constraint, it's a gameplay constraint. Anim8 should not know about this, the same way it doesn't know about sounds played by your game, for example. It's the other way around: it's your game who should be telling animations when they should stop/start/swap etc.

The rule of thumb for using animations is: if you suddently removed all the animations from your game and replaced them by static pictures, your game should still work (it should just show static images).

In the particular case of the "firing can not be interrupted", given that you already (seem to) have states, I would add a new state to the player called "firing". During this state, he doesn't answer to keypresses, but he can probably answer to other things (like getting killed by an enemy shot, or the floor disappearing). When the animation is finished, he can move to a different state.

To control "when the animation has finished", you have several options. The simplest one is using a counter that you increase by dt on every update, and checking whether it's greater than the total duration of the animation. If you find yourself using lots of such counters to handle time very often, I recommend using a some time-management library like [wiki]cron.lua[/wiki] instead of doing it manually.

I do not recommend using the onLoop callback to trigger the switch(that would put control of your gameplay into the animation – leave onLoop for animation-related things, like resetting the frames). As I said before, your game should just work if you removed all animations.
When I write def I mean function.
tehryanx
Prole
Posts: 17
Joined: Fri Apr 04, 2014 8:26 pm

Re: Animation logic using anim8

Post by tehryanx »

Okay, this makes a lot of sense but I'm confused on one aspect. My attack animation has 7 frames. If I'm using a counter to determine when the animations finished, you suggest increasing the counter by dt every frame. Do I then just wait for the counter to be > 7? If I'm calling animation:update() in love.update() then shouldn't I just increase the counter by 1 every time, as this would correspond to 7 updates? Or is 7 calls to animation:update() not the same as 7 frames?
User avatar
verilog
Citizen
Posts: 97
Joined: Thu Nov 03, 2011 3:15 am
Contact:

Re: Animation logic using anim8

Post by verilog »

You might want to count (animation) frames instead of time. The reason for this is that counting directly time can give you slightly errors unless you also take into account the time expended executing code during animation playback. The result of this is that you may end up repeating (or missing) a frame or two. If you count frames, things get a little easier. However, you must know what frame of your animation is currently playing, if you have access to that info, then you can simply check if the animation is finished. Something like:

Code: Select all

 if currentFrame == lastFrame then
--animation has reached the last frame
end
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Animation logic using anim8

Post by kikito »

tehryanx wrote:My attack animation has 7 frames. If I'm using a counter to determine when the animations finished, you suggest increasing the counter by dt every frame. Do I then just wait for the counter to be > 7?
Maybe counter was not the right word. Accumulator might be a better one.

You should not compare it with the number of frames, but with the total time the animation takes to completely execute. So if your frames are 0.1 seconds each, and you have 7 of them, you should compare it with 0.7.

When an animation is initialized it has one parameter called totalAnimation, and you could use that. But I would not use it here, because you that would be tying your gameplay to animation attributes. Instead, I'd do it the other way around: I'd have a variable with the total time that it takes to do the animation, and calculate each frame's duration based on that:

Code: Select all

local attackDuration = 0.7
...
player.animations['attack'] = anim8.newAnimation(grid('1-7',7), attackDuration / 7)
verilog wrote:

Code: Select all

 if currentFrame == lastFrame then
--animation has reached the last frame
end
I don't recommend doing this. To start with, reaching the last frame does not mean that an animation has finished. The last frame has duration, and that duration has to be taken into account before considering that the animation is finished (for all we now the animation could spend hours in the last frame before finishing).

As I said before, your gameplay code should be oblivious to the state of the animation. Instead, do this:

Code: Select all

if accumulator >= attackDuration then
-- Shooting is now cancellable
end
When I write def I mean function.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 6 guests