Animating With Separate Image Files

Started by
14 comments, last by LeftyGuitar 9 years, 9 months ago

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.

Advertisement

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.

Hello to all my stalkers.

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

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.

(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.

Hello to all my stalkers.

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.


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.

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.

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.

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?

This topic is closed to new replies.

Advertisement