• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
ISDCaptain01

how to deal with attacking animation?

15 posts in this topic

I coding a Zelda clone, but I have a problem with attack animation. When I press the attack button it just animates way too fast. I want to slow it down, but everything I have tried hasn't worked. this is my attack animation code:

void Link::attack()
{
	if(linkInput.CheckStateInput(ALLEGRO_KEY_S) && !linkInput.CheckStateInput(ALLEGRO_KEY_DOWN))
	{
		canAttack = true;

		//Ready to attack?
		if(canAttack == true)
		{
		
			//Dont let link move or jump while attacking
			if(jump == JUMPIT)
			{
				linkSprite.x = linkSprite.oldpx;
				linkSprite.y = linkSprite.oldpy;
			}

			if(linkSprite.curframe != 4 || linkSprite.curframe != 5)
				linkSprite.curframe = 4;

			if(++linkSprite.framecount > linkSprite.framedelay)
			{
				linkSprite.framecount = 0;

				if(++linkSprite.curframe == 5)
				{
					if(++attackanimcount < attackanimdelay)
					{
						linkSprite.curframe = 5;
						canAttack = false;
					}
				}
			}
		}
	}
}

I want to slow it down so that I can see the animation complete itself realistically

0

Share this post


Link to post
Share on other sites

You can implement a time-step to slow things down. Right now, your computer is just blowing through your frames as quickly as it can. A time step will also make it run on the same speed if on a faster or slower computer, or even if the resources on the computer you're currently using change:


 frameCounter= 0;
 switchFrame = 100;
 frameSpeed = 800;

frameCounter += frameSpeed * clock.restart().asSeconds();//get elapsed time and restart the clock, add to framecounter.
    if(frameCounter >= switchFrame)
        {
        frameCounter = 0;
        source.x++;/*these are just the texture coordinates for the texture atlas,
                     change it to however it is you're switching textures with curframe in allegro, 
                     like curframe +=1 or whathaveyou.*/
        if(source.x * 200 >= pTex.getSize().x)//resets the animation to first frame
            source.x = 0;
        } 

Basically, you're tying the animation to a clock (clock.restart() gets the elapsed time in SFML while resetting the clock, change to whatever you use currently for time in allegro), and only going to the next frame at a fixed rate. Each time your computer goes through the code, it adds a little to your framecounter (since it's multiplied by the time passed since the last time it ran through the code, the faster it goes through the code, the less it adds, if it's running through slower, it adds more), if it goes over a certain amount, it moves your animation to the next frame and resets the framecounter. When it gets to the end of your frames, it then resets the animation. This way, the animation always runs at the same speed, regardless of how quickly your computer is running, and it also lets you set the rate at which the animation moves. Just alter the switchframe/framespeed values.

 

This example may/may not be all that helpful, but a quick search for time-step animation should turn up plenty of tutorials. This example is for SFML, but it shouldn't be too hard to implement in allegro. If I'm explaining this poorly, let me know and I'll try to be a little clearer.

Edited by Misantes
2

Share this post


Link to post
Share on other sites
dejaime, on 08 Jul 2014 - 11:09 PM, said:

So, from your code I am assuming your attack animation is composed of only two frames, frames #4 and #5.
Is that correct?
 
One thing you can try is resetting your framecount when you change the animation:


One other possibility would be to increase the delay necessary in order to change the frame:
const double animation_delay_modifier = 0.5;
if( ++linkSprite.framecount > linkSprite.framedelay * animation_delay_modifier )
{
	linkSprite.framecount = 0;
	[...]
Maybe I misunderstood your code...
 
if(++linkSprite.curframe == 5)
{
	if(++attackanimcount < attackanimdelay)
	{
		linkSprite.curframe = 5;
		canAttack = false;
	}
}
I didn't get this part. First, you check if the pre-incremented variable equals to 5, but you then make it 5, even though it was already. There may be some confusion here.

 

 

Okay lemme explain this part

if(++linkSprite.curframe == 5) { if(++attackanimcount < attackanimdelay) { linkSprite.curframe = 5; canAttack = false; } }

Basically when the attack animation reaches the final frame, I want it to stay on that frame for the just a lil bit before it resets back to frame 4. that's what attackanimcount and attackanimdelay do. If attackanimcount is less than the delay, keep on staying on frame 5 until it surpasses the delay amount. But looks like it isn't working. Ill try some of the solutions that you and the others mentioned.

0

Share this post


Link to post
Share on other sites

You can implement a time-step to slow things down. Right now, your computer is just blowing through your frames as quickly as it can. A time step will also make it run on the same speed if on a faster or slower computer, or even if the resources on the computer you're currently using change:


while i agree with everything you've said, i don't believe this is his problem. if he has vsync on then that will basically act as his timer, and without seeing the rest of his code, it's impossible to say if he does or does not use a timer(likely he does not though). so i think he should follow your post, but in this instance i don't believe that is his issue.
 
edit: however, upon re-reading your code, you should not be setting frameCounter back to 0, instead subtract switchFrame from that counter. this is because by setting it to 0, you lose any amount of time that has accumulated past switchFrame. for example, let's say on the first frame you get 15ms, just shy of 16ms to run at 60fps, the os switchs away, then switchs back, this took 18ms to do, so now frameCounter is at 33ms, this would be two complete frames, with an extra ms into the third but you only process one frame, then reset frameCounter to 0, which loses all that accumulated time.

Okay lemme explain this part

if(++linkSprite.curframe == 5) { if(++attackanimcount < attackanimdelay) { linkSprite.curframe = 5; canAttack = false; } }
Basically when the attack animation reaches the final frame, I want it to stay on that frame for the just a lil bit before it resets back to frame 4. that's what attackanimcount and attackanimdelay do. If attackanimcount is less than the delay, keep on staying on frame 5 until it surpasses the delay amount. But looks like it isn't working. Ill try some of the solutions that you and the others mentioned.


let me reiterate, that part of your code doesn't do anything, when you explicitly set the frame back to 4 on each frame:
 
if(linkSprite.curframe != 4 || linkSprite.curframe != 5)
linkSprite.curframe = 4;
this is basically saying: "hey, am i not 4? then set me to 4. hey, am i also not 5? then set me to 4." this logic will run on every single frame because a variable can not be 2 values at once. because this line is before that other logic, it's possible for you to achieve a single-frame on frame 5, but if you are running at 60 fps, you'll see this on screen for a mere 16ms of time.

also, a couple other things you should note:
-setting canAttack = true at the start of your function negates setting it to false at the end, and makes the if(canAttack==true) logic pointless.
-you will only animate while holding down the down or S key, so i'd recommend moving your animation code outside of your input logic code.

i'm not going to fix your code completely, but as it is, a simple change like so should get you your desired result:
 
void Link::attack()
{
    if(linkInput.CheckStateInput(ALLEGRO_KEY_S) && !linkInput.CheckStateInput(ALLEGRO_KEY_DOWN))
    {
        canAttack = true;
        //Ready to attack?
        if(canAttack == true)
        {
            //Dont let link move or jump while attacking
            if(jump == JUMPIT)
            {
                linkSprite.x = linkSprite.oldpx;
                linkSprite.y = linkSprite.oldpy;
            }
            if(++linkSprite.framecount > linkSprite.framedelay)
            {
                linkSprite.framecount = 0;
                linkSprite.curframe++;
                if(linkSprite.curframe==6) linkSprite.curframe = 4; //we go back to 4 once we've passed the 5th frame.
            }
        }
    }
}
Edited by slicer4ever
2

Share this post


Link to post
Share on other sites


edit: however, upon re-reading your code, you should not be setting frameCounter back to 0, instead subtract switchFrame from that counter. this is because by setting it to 0, you lose any amount of time that has accumulated past switchFrame. for example, let's say on the first frame you get 15ms, just shy of 16ms to run at 60fps, the os switchs away, then switchs back, this took 18ms to do, so now frameCounter is at 33ms, this would be two complete frames, with an extra ms into the third but you only process one frame, then reset frameCounter to 0, which loses all that accumulated time.

 

Could you clarify this (I'm not being argumentative, I'm newish myself, and just want to make sure I'm not doing things wrong myself here)? I was operating under the impression that this was the point of doing it this way. For my physics and main function time-step, I generally do do things the way you suggest, by subtracting time passed, but for animation, I was doing things this way because I wanted several frames to pass between updating the animation (for simple animations it's generally way to quick to update on each pass). I understand that any time accumulated over the point where it switches is lost and would be better to add that back into the framecounter, but I find in practice, since it happens at a pretty steady rate, and no physics are involved, it isn't noticeable (and also didn't want to make this example any more complicated). I've been resetting to zero so that several more passes  occur through the code occur before it switches frames again. So, the loss of accumulated time would be intentional (excepting the time that goes over the framecounter "if >=" point).

 

And, I don't mean to derail the thread, if you're still correct, feel free to just pm me so we don't change the OP's topic.

0

Share this post


Link to post
Share on other sites

You really need to have each animation frame stay on the screen for a certain time duration (not number of frames...), and move to the next frame after that time has expired. I'd suggest storing your animation frames, and the times they should stay on, in an external data file (json or XML), and using that file for all your animations.

 

This will allow you to work with fast framerate machines or slow framerate machines.

2

Share this post


Link to post
Share on other sites

edit: however, upon re-reading your code, you should not be setting frameCounter back to 0, instead subtract switchFrame from that counter. this is because by setting it to 0, you lose any amount of time that has accumulated past switchFrame. for example, let's say on the first frame you get 15ms, just shy of 16ms to run at 60fps, the os switchs away, then switchs back, this took 18ms to do, so now frameCounter is at 33ms, this would be two complete frames, with an extra ms into the third but you only process one frame, then reset frameCounter to 0, which loses all that accumulated time.

 
Could you clarify this (I'm not being argumentative, I'm newish myself, and just want to make sure I'm not doing things wrong myself here)? I was operating under the impression that this was the point of doing it this way. For my physics and main function time-step, I generally do do things the way you suggest, by subtracting time passed, but for animation, I was doing things this way because I wanted several frames to pass between updating the animation (for simple animations it's generally way to quick to update on each pass). I understand that any time accumulated over the point where it switches is lost and would be better to add that back into the framecounter, but I find in practice, since it happens at a pretty steady rate, and no physics are involved, it isn't noticeable (and also didn't want to make this example any more complicated). I've been resetting to zero so that several more passes  occur through the code occur before it switches frames again. So, the loss of accumulated time would be intentional (excepting the time that goes over the framecounter "if >=" point).
 
And, I don't mean to derail the thread, if you're still correct, feel free to just pm me so we don't change the OP's topic.


this might differ by each person's expectations of what a game should be. for me, personally, i try to make all my games deterministic in nature, this includes animation. if you are working at a fixed time-step, then for a game you can start thinking of animations in terms of gameplay ticks, where 1 tick = 1/Frequency of time-step. this can greatly simplify the entire animation system when you no longer think in terms of seconds, but in terms of ticks(for example, let's say i have an animation that runs 1.5 seconds, on completion i should do a task, this means that for each frame i check to see if the animation has finished. if i'm running at 1/5th a second per frame, this means that depending on how much accumulation time, that task could occur on the 7th or 8th frame since the animation was started, however if i say it will finish in 8 frames(so 1.6 seconds), then i can always know that it will fire the event 8 frames after the animation). this also has the added advantage in that you can change the frequency to be faster/slower and all animations will adequately run at the different simulation speed with the overall game.

now some of you might be saying: "well, what happens if the pc can't keep up with your targeted framerate?". that's a valid point, however if you are running gameplay and rendering logic in different threads(and hopefully your target platform has multiple core's), i've generally found that for nearly all game's i've ever built, the actual game logic itself uses a very tiny fraction of cpu time, compared to the rendering logic.

for example, when developing a PSM game, i found that doing transformations of the asteroid/player ship was faster to do on the cpu, then it was on the gpu for low-end devices such as the tablet P, or xperia play. this is because i was also doing a full screen 2-pass gaussian blur, which ate up alot of my rendering time, by doing the vertex transformations on cpu(this was ~500 asteroids, or ~15000 vertices), i freed up enough render time to do that 2-pass blur and still maintain a solid 60 fps.
0

Share this post


Link to post
Share on other sites

Well I got it to partially work as the animation is a lot slower, but it still seems like it flies off frame 5 bit too fast:

void Link::attack()
{
	if(linkInput.CheckStateInput(ALLEGRO_KEY_S) && !linkInput.CheckStateInput(ALLEGRO_KEY_DOWN))
	{
		canAttack = true;

		//Dont let link move or jump while attacking
		if(jump == JUMPIT)
		{
			linkSprite.x = linkSprite.oldpx;
			linkSprite.y = linkSprite.oldpy;
		}

		if(++linkSprite.framecount > linkSprite.framedelay)
		{
			linkSprite.framecount = 0;

			if(++linkSprite.curframe > 4)
			{
				if(++attackanimcount < attackanimdelay)
					linkSprite.curframe = 4;
				else
				{
					linkSprite.curframe = 5;
					attackanimcount = 0;
				}
			}
				
			else if(++linkSprite.curframe == 5)
			{
				if(++attackanimcount < attackanimdelay)
					linkSprite.curframe = 5;
				else
				{
					linkSprite.curframe = 0;
					attackanimcount = 0;
				}
			}
			else if(++linkSprite.curframe == 6)
				linkSprite.curframe = 4;
		}	
	}
	else
	{
		canAttack = false;
	}
}

But it seems like its interfering with my moving code:

//the basic controls for link
void Link::moveLink()
{
	//Record previous positions
	linkSprite.oldpx = linkSprite.x;
	linkSprite.oldpy = linkSprite.y;

	//Move right and animate
	if(linkInput.CheckStateInput(ALLEGRO_KEY_RIGHT))
	{
		linkSprite.direction = right;
		linkSprite.x += linkSprite.velx;

		if(++linkSprite.framecount > linkSprite.framedelay)
		{
			linkSprite.framecount = 0;

			if(++linkSprite.curframe > 3)
			{
				linkSprite.curframe = 0;
			}
		}
	}

	//Move left and animate
	else if(linkInput.CheckStateInput(ALLEGRO_KEY_LEFT))
	{
		linkSprite.direction = left;
		linkSprite.x -= linkSprite.velx;

		if(++linkSprite.framecount > linkSprite.framedelay)
		{
			linkSprite.framecount = 0;

			if(++linkSprite.curframe > 3)
			{
				linkSprite.curframe = 0;
			}
		}
	}

	//Duck
	else if(linkInput.CheckStateInput(ALLEGRO_KEY_DOWN))
	{
		linkSprite.curframe = 6;

		if(linkInput.CheckStateInput(ALLEGRO_KEY_DOWN))
		{
			if(linkInput.CheckStateInput(ALLEGRO_KEY_S))
				linkSprite.curframe = 7;
		}
	}

	//When doing nothing, just stand
	else 
	{
		if(!canAttack)
			linkSprite.curframe = 0;
	}
}
Edited by ISDCaptain01
0

Share this post


Link to post
Share on other sites

Well i found this algorithm, ill try it tonight:

bool hold_animation;
double hold_animation_delay;
double time_elapsed;

if (hold_animation) {
time_elapsed += delta_time;
if (time_elapsed > hold_animation_delay) {
hold_animation = false;
++frame;
}
else {
// do nothing, don't advance frame
}
}
else {
++frame;// animation_time += delta_time;
}
0

Share this post


Link to post
Share on other sites
I'd highly recommend you remove all the different animation code, and centralize the animation structure/code logic to one area where you define it. as you stand now, your animation code looks to be all over the place, and as you can see it's beginning to screw you in that department.

basically, animations should run kindof independent to your input logic.

an example of that would be something like:

   object->processInput();
   object->UpdateAnimation();
all your framecount/framedelay/current frame stuff should be updated solely from inside UpdateAnimation. it's kindof ok to arbitrarily set your current frame from other parts of your gameplay logic(and truthfully this should be more of setting what animation you want to play, not the exact frame to play on). but you should not be arbitrarily controlling the actual animation updating from these other components. Edited by slicer4ever
0

Share this post


Link to post
Share on other sites

Heck Yeah, I got it to work:

void Link::doAttack()
{
	if(canAttack)
	{
		attackanimcount++;
		if(attackanimcount > attackanimdelay)
		{
			canAttack = false;
			attackanimcount = 0;
		}
		else
		{
			linkSprite.curframe = 5;
		}
	}
	/*else
	{
	}*/
}
0

Share this post


Link to post
Share on other sites

got it to work even better, awesome. heres the code if anyone wants to see:

void Link::doAttack()
{

	if(canAttack)
	{
		attackanimcount++;
		if(attackanimcount > attackanimdelay)
		{
			part1++;
			attackanimcount = 0;

			if(part1 > 1)
			{
				canAttack = false;
				attackanimcount = 0;
				part1 = 0;
			}
		}
		else
		{
			if(part1 == 0)
				linkSprite.curframe = 4;
			else if(part1 == 1)
				linkSprite.curframe = 5;
		}
	}
}
0

Share this post


Link to post
Share on other sites

 

got it to work even better, awesome. heres the code if anyone wants to see:

void Link::doAttack()
{

	if(canAttack)
	{
		attackanimcount++;
		if(attackanimcount > attackanimdelay)
		{
			part1++;
			attackanimcount = 0;

			if(part1 > 1)
			{
				canAttack = false;
				attackanimcount = 0;
				part1 = 0;
			}
		}
		else
		{
			if(part1 == 0)
				linkSprite.curframe = 4;
			else if(part1 == 1)
				linkSprite.curframe = 5;
		}
	}
}

Glad to hear, but, again, be aware, this will only work if your game logic update is called at a specific rate.  I don't really understand why you wouldn't use time to determine when to change frames, or allow attacking, rather than some unscientific frame count value.

 

But, if you're happy with it, good to hear :)

0

Share this post


Link to post
Share on other sites
I did some testing and ran my game at 120fps and everything speeded up accordingly. I will experiment with what you said but for now i needed this quick and easy solution
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0