Jump to content

  • Log In with Google      Sign In   
  • Create Account

Animating With Separate Image Files


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 06 July 2014 - 01:46 PM

Hello,

 

I am having trouble getting separate image files to animate smoothley. When I run the program, the image shows up and flickers alot, it also stutters some. I'll post some of my code and see if anyone can help me.

		SDL_RenderClear(MainRend);

		SDL_RenderCopy(MainRend,BackdropTex,NULL,&BackdropRect);

		gAidan.CurrentFrame++;
		if(gAidan.CurrentFrame == 1)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[0],NULL,&gAidan.StandDstRect[0]);
		}
		else if(gAidan.CurrentFrame == 2)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[1],NULL,&gAidan.StandDstRect[1]);
		}
		else if(gAidan.CurrentFrame == 3)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[2],NULL,&gAidan.StandDstRect[2]);
		}
		else if(gAidan.CurrentFrame == 4)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[3],NULL,&gAidan.StandDstRect[3]);
		}
		else if(gAidan.CurrentFrame == 5)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[4],NULL,&gAidan.StandDstRect[4]);
		}
		else if(gAidan.CurrentFrame == 6)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[5],NULL,&gAidan.StandDstRect[5]);
		}
		else if(gAidan.CurrentFrame == 7)
		{
			gAidan.CurrentFrame = 0;
		}

		SDL_RenderPresent(MainRend);

I can post more code if it is needed.



Sponsor:

#2 Lactose!   GDNet+   -  Reputation: 3392

Like
3Likes
Like

Posted 06 July 2014 - 01:55 PM

If this code is executed once per render loop, the image will NOT be drawn 1 frame every 7 frames. This is what causes the flicker.

This is because if CurrentFrame is 6 upon entering this code, it will be incremented to 7. It will then bypass all the other ifs, and go to the == 7 part.

Here, it will be set to 0 (so that it runs 1 next loop), but it will not do any drawing this loop.

You can fix this by doing a separate if check right after incrementing, that sets it to 1.

 

However, there is a lot of (almost) identical code here. You could change all of the above (with the fix I mentioned) into the following:

SDL_RenderClear(MainRend);
SDL_RenderCopy(MainRend,BackdropTex,NULL,&BackdropRect);
 
SDL_RenderCopy(MainRend,gAidan.StandTex[gAidan.CurrentFrame],NULL,&gAidan.StandDstRect[gAidan.CurrentFrame])
 
gAidan.CurrentFrame++;
gAidan.CurrentFrame %= 7;
 
SDL_RenderPresent(MainRend);

If this looks a bit like magic, ask and I'll explain what's going on.


Edited by Lactose!, 06 July 2014 - 01:55 PM.


#3 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 06 July 2014 - 02:12 PM

Thanks, I can see what's going on with the code.



#4 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 06 July 2014 - 05:59 PM

Hello again,

 

I am having trouble getting my image to move. I have it so that when the user presses a key, the character moves left or right. When I press either of those keys, the animation plays, but the character does not move. I'll post my code.

const float MOVEMENT_SPEED = 0.10f;
			
if(event.type == SDL_KEYDOWN && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_ESCAPE)
				{
					GameRunning = false;
				}

				if(event.key.keysym.sym == SDLK_LEFT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.WalkingDstRect[gAidan.CurrentFrame].x -= (int)gAidan.X_Vel * (int)MOVEMENT_SPEED;
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.WalkingDstRect[gAidan.CurrentFrame].x += (int)gAidan.X_Vel * (int)MOVEMENT_SPEED;
				}
			}

void Render()
{
		SDL_RenderClear(MainRend);

		SDL_RenderCopy(MainRend,BackdropTex,NULL,&BackdropRect);

		SDL_RenderCopy(MainRend,gAidan.StandTex[gAidan.CurrentFrame],NULL,&gAidan.StandDstRect[gAidan.CurrentFrame]);

		gAidan.CurrentFrame++;
		gAidan.CurrentFrame = SDL_GetTicks() / 100 % 6;

		if(gAidan.Action == gAidan.WALKING)
		{
			SDL_RenderCopy(MainRend,gAidan.WalkingTex[gAidan.CurrentFrame],NULL,&gAidan.WalkingDstRect[gAidan.CurrentFrame]);

			gAidan.CurrentFrame++;
			gAidan.CurrentFrame = SDL_GetTicks() / 100 % 6;
		}

		SDL_RenderPresent(MainRend);
}

I can post more code if it is needed.



#5 Lactose!   GDNet+   -  Reputation: 3392

Like
0Likes
Like

Posted 06 July 2014 - 06:15 PM

(int)MOVEMENT_SPEED takes the float variable 0.10f and casts it to an integer value. Since integer values can't represent decimal values, the value you end up with is 0.

Whatever X_Vel is, it will be multiplied by 0, which results in 0 movement.

 

Either store the position as a float (and cast to int if needed for rendering only), OR multiply as floats first, and cast the result of the float multiply to an int.

Depending on the variable values, the second option might not work (it might still get truncated to 0 when cast to int).

 

I would recommend using the first option.



#6 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 06 July 2014 - 06:56 PM

I'm still confused here. I changed the position variables to integer values, and the character still won't move. Though the animation does play. Also, after the I close the program, I get some kinda of memory leak error or something.



#7 haegarr   Crossbones+   -  Reputation: 4313

Like
1Likes
Like

Posted 07 July 2014 - 12:51 AM


I changed the position variables to integer values, and the character still won't move.

What Lactose! wrote means that the casting to int makes the value of the effective speed to be zero, and multiplying with zero gives zero, and adding zero does not change anything:

 

1.)  const float MOVEMENT_SPEED = 0.10f;

=> MOVEMENT_SPEED = 0.1

 

2.) gAidan.WalkingDstRect[gAidan.CurrentFrame].x -= (int)gAidan.X_Vel * (int)MOVEMENT_SPEED;

=> (int)MOVEMENT_SPEED => (int)0.1 => (int)round(0.1) => (int)0 => 0

=> no change, because gAidan.WalkingDstRect[gAidan.CurrentFrame].x -= 0 

 

What you need to do instead is:

With gAidan.X_Pos being a float, and gAidan.X_Vel being a float, and MOVEMENT_SPEED being a float:

 

1.) updating position (notice that only floats are used, so above problem is avoided)

gAidan.X_Pos -= gAidan.X_Vel * MOVEMENT_SPEED;

 

2.) later, for rendering

gAidan.WalkingDstRect[gAidan.CurrentFrame].x = (int)gAudan.X_Pos;

 

BTW: With small enough numbers the integer value of X_Pos may change after a few frames only, but that would be totally correct.


Edited by haegarr, 07 July 2014 - 12:55 AM.


#8 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 07 July 2014 - 10:36 AM

Thanks for the help. I've tried those, and it still just stays in place while playing the animation.

 

gAiden.X_Pos = 0.15f;

gAiden.Y_Pos = 0.15f;

MOVEMENT_SPEED = 0.10f;

 

Those are the values I have set for those variables.



#9 haegarr   Crossbones+   -  Reputation: 4313

Like
0Likes
Like

Posted 07 July 2014 - 10:48 AM

gAiden.X_Pos = 0.15f;
gAiden.Y_Pos = 0.15f;
MOVEMENT_SPEED = 0.10f;
 
Those are the values I have set for those variables.

X_Pos and Y_Pos are irrelevant for the calculations, but X_Vel and Y_Vel are not. Have you confused those names? If not, what are the values of X_Vel and Y_Vel?

 

If you read my post above carefully, then you should understand that integer values have no decimal digits! If you have a X_Vel of 0.15 and a speed of 0.1, then each step is as wide as 0.015. Rounding occurs at 0.5, so you need to accumulate 0.015 for 34 times to see it move 1 pixel the first time.

 

 

EDIT: Ugh, I forgot that casting to integer doesn't round but truncates. In that case the first movement will of course happen when the accumulation exceeds 1.0 but not 0.5. However, that has no influence on the principle.


Edited by haegarr, 07 July 2014 - 11:00 AM.


#10 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 07 July 2014 - 11:51 AM

Ooops, I'm sorry, Those are the values of X_Vel and Y_Vel.

 

X_Vel = 0.15f;

Y_Vel = 0.15f;

X_Pos = 10;

Y_Pos = 100;

 

    gAidan.WalkingDstRect[0].x = gAidan.X_Pos;
    gAidan.WalkingDstRect[0].y = gAidan.Y_Pos;

 

I'm wondering now, should I change to where it says gAidan.WalkingDstRect[0].x = gAidan.X_Pos to gAidan.WalkingDstRect[gAidan.CurrentFrame].x = gAidan.x_Pos?



#11 Lactose!   GDNet+   -  Reputation: 3392

Like
0Likes
Like

Posted 07 July 2014 - 12:27 PM

What's the type for X_Pos and Y_Pos? Are they int or float?

 

EDIT: I ask because your value assignments make it look like they're still int. This will have the same problem as before (no change in position), if X_Vel * MOVEMENT_SPEED is less than 1 (and won't behave as expected except for values that can be represented as integers).


Edited by Lactose!, 07 July 2014 - 01:12 PM.


#12 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 07 July 2014 - 01:38 PM

Sorry, I should have specified the variable types as well.

 

X_Pos and Y_Pos are ints.

X_Vel and Y_Vel are floats.

 

I also did trying changing gAidan.WalkingDstRect[0].x = gAidan.X_Pos to gAidan.WalkingDstRect[gAidan.CurrentFrame].x = gAidan.x_Pos, but that didn't seem to help me.



#13 haegarr   Crossbones+   -  Reputation: 4313

Like
0Likes
Like

Posted 07 July 2014 - 02:32 PM

X_Pos and Y_Pos are ints

Well ...

What you need to do instead is:
With gAidan.X_Pos being a float, and gAidan.X_Vel being a float, and MOVEMENT_SPEED being a float:
...

1.) updating position (notice that only floats are used, so above problem is avoided)

gAidan.X_Pos -= gAidan.X_Vel * MOVEMENT_SPEED;

(bolded for emphasizing). The accumulation need to be done on float if you want to have an effect at all when increasing by values less than 1.


Edited by haegarr, 07 July 2014 - 02:35 PM.


#14 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 07 July 2014 - 06:34 PM

OK, I'm just puzzled here. Here is a bigger chunk of code, perhaps I am doing something wrong, and not noticing it? I have the gAidan.WalkingDstRect[].x = gAidan.X_Pos,

same for the Y coordinate rectangle box as well. I've left the width and height of it by 400x400. So it looks like this

 

gAidan.WalkingDstRect[0].x = gAidan.X_Pos;

gAidan.WalkingDstRect[0].y = gAidan.Y_Pos;

gAidan.WalkingDstRect[0].w = 400;

gAidan.WalkingDstRect[0].h = 400;

 

I've tried a lot of different things, but for whatever reason, it just won't move. It stays in place while the animation plays.

void RunGame()
{
	while(GameRunning)
	{
		CurrentTime = SDL_GetTicks();
		DeltaTime = (float)(CurrentTime - LastTime) / MAX_TICKS;
		LastTime = CurrentTime;

		while(SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT)
			{
				GameRunning = false;
			}

			if(event.type == SDL_KEYDOWN && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_ESCAPE)
				{
					GameRunning = false;
				}

				if(event.key.keysym.sym == SDLK_LEFT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.X_Pos -= gAidan.X_Vel * DeltaTime;
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.X_Pos += gAidan.X_Vel * DeltaTime;
				}

				if(event.key.keysym.sym == SDLK_UP)
				{
					gAidan.Action = gAidan.JUMP_A;
				}
				else if(event.key.keysym.sym == SDLK_DOWN)
				{
					gAidan.Action = gAidan.CROUCH;
				}
			}

			if(event.type == SDL_KEYUP && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_LEFT)
				{
					gAidan.X_Vel = 0.0f;
					gAidan.Action = gAidan.STANDING;
					
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					gAidan.X_Vel = 0.0f;
					gAidan.Action = gAidan.STANDING;
					
				}
			}
		}

		Update();

		Render();
	}
}

void Update()
{
	gAidan.WalkingDstRect[gAidan.CurrentFrame].x = (int)gAidan.X_Pos;
}

void Render()
{
		SDL_RenderClear(MainRend);

		SDL_RenderCopy(MainRend,BackdropTex,NULL,&BackdropRect);

		if(gAidan.Action == gAidan.STANDING)
		{
			SDL_RenderCopy(MainRend,gAidan.StandTex[gAidan.CurrentFrame],NULL,&gAidan.StandDstRect[gAidan.CurrentFrame]);

			gAidan.CurrentFrame++;
			gAidan.CurrentFrame = SDL_GetTicks() / 100 % 5;
		}

		if(gAidan.Action == gAidan.WALKING)
		{
			SDL_RenderCopy(MainRend,gAidan.WalkingTex[gAidan.CurrentFrame], NULL, &gAidan.WalkingDstRect[gAidan.CurrentFrame]);

			gAidan.CurrentFrame++;
			gAidan.CurrentFrame = SDL_GetTicks() / 100 % 5;
		}

		SDL_RenderPresent(MainRend);
}


#15 L. Spiro   Crossbones+   -  Reputation: 13600

Like
0Likes
Like

Posted 07 July 2014 - 07:06 PM

You are only modifying its position when an event is polled.
That means every time you press SDLK_LEFT it moves “gAidan.X_Vel * DeltaTime” exactly once.
Even if gAidan.X_Vel is not 0, DeltaTime is likely going to be around 0.1666 or something, so you are probably moving less than a pixel.
 
But that’s assuming gAidan.X_Vel is not 0.  But it is 0.  You set it to 0 in many places.  You set it to non-zero in no places.
 
 
 

void RunGame()
{
	while(GameRunning)
	{
		CurrentTime = SDL_GetTicks();
		DeltaTime = (float)(CurrentTime - LastTime) / MAX_TICKS;
		LastTime = CurrentTime;

		while(SDL_PollEvent(&event))
		{
			if(event.type == SDL_QUIT)
			{
				GameRunning = false;
			}

			if(event.type == SDL_KEYDOWN && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_ESCAPE)
				{
					GameRunning = false;
				}

				if(event.key.keysym.sym == SDLK_LEFT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.X_Vel = -20.0f;
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					gAidan.Action = gAidan.WALKING;
					gAidan.X_Vel = 20.0f;
				}

				if(event.key.keysym.sym == SDLK_UP)
				{
					gAidan.Action = gAidan.JUMP_A;
				}
				else if(event.key.keysym.sym == SDLK_DOWN)
				{
					gAidan.Action = gAidan.CROUCH;
				}
			}

			if(event.type == SDL_KEYUP && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_LEFT)
				{
					gAidan.X_Vel = 0.0f;
					gAidan.Action = gAidan.STANDING;
					
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					gAidan.X_Vel = 0.0f;
					gAidan.Action = gAidan.STANDING;
					
				}
			}
		}
 		gAidan.X_Pos += gAidan.X_Vel * DeltaTime;
		Update();

		Render();
	}
}

 

L. Spiro


Edited by L. Spiro, 07 July 2014 - 07:07 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#16 LeftyGuitar   Members   -  Reputation: 186

Like
0Likes
Like

Posted 07 July 2014 - 07:58 PM

Thanks. That got it to move a little, but it only moves about a few pixels, then it stays still and plays the animations.






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS