Sign in to follow this  

Increment Frame Bug

This topic is 1207 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

I am having trouble fixing this bug. It appears that when the character is facing a any direction, but up, and the user presses the attack key, the program crashes. The errors I am getting are      SDL2.dll!6c778e1b()    Unknown and      [Frames below may be incorrect and/or missing, no symbols loaded for SDL2.dll]  I assume this is because when I check for the frame increment, it stays as zero. I added a watch to it, it does not appearing to be incrementing, even though it is coded to do so. I'll post some code and see if I'm doing anything wrong? Note, that for each direction, there is only 3 frames for attacking. I can provide more info if it is needed.

const float HERO_MAX_X_VEL = 5.0f;
const float HERO_MAX_Y_VEL = 5.0f;

const int MAX_FPS = 60;
const int MAX_TICKS = 1000;

    Hero.Width = 48;
    Hero.Height = 63;
    Hero.CurrentFrame = 0;

    Hero.XVel = 0.0f;
    Hero.YVel = 0.0f;

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)
				{
					Hero.CurrentState = Hero.WALK_LEFT;
					Hero.Facing = Hero.LEFT;
					Hero.XVel -= HERO_MAX_X_VEL;
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					Hero.CurrentState = Hero.WALK_RIGHT;
					Hero.Facing = Hero.RIGHT;
					Hero.XVel += HERO_MAX_X_VEL;
				}

				if(event.key.keysym.sym == SDLK_UP)
				{
					Hero.CurrentState = Hero.WALK_UP;
					Hero.Facing = Hero.UP;
					Hero.YVel -= HERO_MAX_Y_VEL;
				}
				else if(event.key.keysym.sym == SDLK_DOWN)
				{
					Hero.CurrentState = Hero.WALK_DOWN;
					Hero.Facing = Hero.DOWN;
					Hero.YVel += HERO_MAX_Y_VEL;
				}

				if(event.key.keysym.sym == SDLK_z)
				{
					Hero.CurrentState = Hero.ATTACK;
				}
			}

			if(event.type == SDL_KEYUP && event.key.repeat == 0)
			{
				if(event.key.keysym.sym == SDLK_LEFT)
				{
					Hero.CurrentState = Hero.IDLE_LEFT;
					Hero.Facing = Hero.LEFT;
					Hero.XVel += HERO_MAX_X_VEL;
				}
				else if(event.key.keysym.sym == SDLK_RIGHT)
				{
					Hero.CurrentState = Hero.IDLE_RIGHT;
					Hero.Facing = Hero.RIGHT;
					Hero.XVel -= HERO_MAX_X_VEL;
				}

				if(event.key.keysym.sym == SDLK_UP)
				{
					Hero.CurrentState = Hero.IDLE_UP;
					Hero.Facing = Hero.UP;
					Hero.YVel += HERO_MAX_Y_VEL;
				}
				else if(event.key.keysym.sym == SDLK_DOWN)
				{
					Hero.CurrentState = Hero.IDLE_DOWN;
					Hero.Facing = Hero.DOWN;
					Hero.YVel -= HERO_MAX_Y_VEL;
				}

				if(event.key.keysym.sym == SDLK_z && Hero.Facing == Hero.UP)
				{
					Hero.CurrentState = Hero.IDLE_UP;
				}
				else if(event.key.keysym.sym == SDLK_z && Hero.Facing == Hero.DOWN)
				{
					Hero.CurrentState = Hero.IDLE_DOWN;
				}
			}

ThisTime = SDL_GetTicks();
	DeltaTime = (float)(ThisTime - LastTime) / MAX_TICKS * MAX_FPS;
	LastTime = ThisTime;

	if(Hero.CurrentState == Hero.WALK_LEFT || Hero.CurrentState == Hero.WALK_RIGHT)
	{
		Hero.XPos += Hero.XVel * DeltaTime;

		if(Hero.XPos <= 0 || (Hero.XPos + Hero.Width > MAX_WIDTH))
		{
			Hero.XPos -= Hero.XVel;
		}
	}

	if(Hero.CurrentState == Hero.WALK_UP || Hero.CurrentState == Hero.WALK_DOWN)
	{
		Hero.YPos += Hero.YVel * DeltaTime;

		if(Hero.YPos <= 0 || (Hero.YPos + Hero.Height > MAX_HEIGHT))
		{
			Hero.YPos -= Hero.YVel;
		}
	}

for(int i = 0; i <= 3; i++)
	{
		Hero.UpAttackRect[i].x = (int)Hero.XPos;
		Hero.UpAttackRect[i].y = (int)Hero.YPos;
		Hero.UpAttackRect[i].w = Hero.Width;
		Hero.UpAttackRect[i].h = Hero.Height;

		Hero.DownAttackRect[i].x = (int)Hero.XPos;
		Hero.DownAttackRect[i].y = (int)Hero.YPos;
		Hero.DownAttackRect[i].w = Hero.Width;
		Hero.DownAttackRect[i].h = Hero.Height;

		Hero.SideAttackRect[i].x = (int)Hero.XPos;
		Hero.SideAttackRect[i].y = (int)Hero.YPos;
		Hero.SideAttackRect[i].w = Hero.Width;
		Hero.SideAttackRect[i].h = Hero.Height;
	}

	if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.DOWN)
	{
		SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]);
		Hero.CurrentFrame++; //debugger says this line for this one
	}

	
if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.LEFT)
	{
		SDL_RenderCopy(GameRend,Hero.SideAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3], NULL,&Hero.SideAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]); //Debugger says it is from this line
		Hero.CurrentFrame++;
	}
Edited by LeftyGuitar

Share this post


Link to post
Share on other sites


SDL2.dll!6c778e1b() Unknown and [Frames below may be incorrect and/or missing, no symbols loaded for SDL2.dll]

Those aren't error messages; that's part of a stack trace. Please post the full output.

Share this post


Link to post
Share on other sites

Oops, sorry, here is the full trace result.

 

First-chance exception at 0x6C778E1B (SDL2.dll) in KnightsReverie.exe: 0xC0000005: Access violation reading location 0x0000003F.
Unhandled exception at 0x6C778E1B (SDL2.dll) in KnightsReverie.exe: 0xC0000005: Access violation reading location 0x0000003F.
The program '[0x3F1C] KnightsReverie.exe' has exited with code 0 (0x0).

     SDL2.dll!6c778e1b()    Unknown
     [Frames below may be incorrect and/or missing, no symbols loaded for SDL2.dll]    
>    KnightsReverie.exe!Render() Line 599    C++
     KnightsReverie.exe!RunGame() Line 425    C++
     KnightsReverie.exe!SDL_main(int argc, char * * argv) Line 60    C++
     KnightsReverie.exe!main(int argc, char * * argv) Line 140    C
     KnightsReverie.exe!__tmainCRTStartup() Line 536    C
     kernel32.dll!@BaseThreadInitThunk@12()    Unknown
     ntdll.dll!___RtlUserThreadStart@8()    Unknown
     ntdll.dll!__RtlUserThreadStart@8()    Unknown

SDL_RenderCopy(GameRend,Hero.SideAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3], NULL,&Hero.SideAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]); //This is line 599

 

Edited by LeftyGuitar

Share this post


Link to post
Share on other sites


it does not appearing to be incrementing, even though it is coded to do so

Actually it isn't. Let's take a look at the code:

 


SDL_RenderCopy(GameRend,Hero.SideAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3], NULL,&Hero.SideAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]); //Debugger says it is from this line
Hero.CurrentFrame++;

 

I emphasized the relevant parts, the last thing you are doing is increment the current frame, which is what you probably want, but you are assigning SDL_GetTicks) / 200 % 3 before that, so your increment will have no effect on that piece.

 

As for the error, are you sure the textures are (properly) initialized? Also it isn't strange you are getting 0 as a result of that calculation. SDL_GetTicks() returns a UInt32 representing how long the program has been running in milliseconds. Most of your divisions with the modulo will result in 0. Check the output if your calculation in a printf to see what comes out of it.

 

You probably just want to have the Hero.CurrentFrame in there and increment when needed, with a check that it doesn't go out of bounds.

 

Hope it helps.

Share this post


Link to post
Share on other sites

Your error is related to a NULL pointer.  It has nothing to do directly with the frame count.  You should investigate it via your debugger.
 
 
As for your frame-count issue, look at the obvious flaw in your code:

	if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.DOWN)
	{
		SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]);
		Hero.CurrentFrame++; //debugger says this line for this one
	}

Hero.CurrentFrame = X followed by Hero.CurrentFrame++. Hero.CurrentFrame is obviously always going to be X + 1 after both lines are executed.

Not only that but you are modifying it twice between sequence points, which is undefined.
Not only that but SDL_GetTicks() is called twice in the call to SDL_RenderCopy(), and could return different results in both calls.




SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]);

could evaluate to:

SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = 564016 / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = 564015 / 200 % 3]);

for example.

Not only that but SDL_GetTicks() returns the number of milliseconds since the SDL library was started. If this code is executed exactly 1 minute and 1 second after the SDL library is started, the call would evaluate to this:

SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = 61000 / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = 61000 / 200 % 3]);

which is the same as writing:

Hero.CurrentFrame = 1;
SDL_RenderCopy(GameRend,Hero.DownAttackTex[1],NULL,&Hero.DownAttackRect[1]);

which means the animation begins on the second frame.

And if we evaluated the full logic of that:

	if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.DOWN)
	{
		SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3],NULL,&Hero.DownAttackRect[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3]);
		Hero.CurrentFrame++; //debugger says this line for this one
	}

becomes:

	if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.DOWN)
	{
		Hero.CurrentFrame = 1;
		SDL_RenderCopy(GameRend,Hero.DownAttackTex[1],NULL,&Hero.DownAttackRect[1]);
		Hero.CurrentFrame = 2;	// Hero.CurrentFrame++;
	}

such that Hero.CurrentFrame is statically assigned to X + 1 (2) as I mentioned.


You have a huge mess of logic here.
#1: You’re assigning to Hero.CurrentFrame for no reason (twice) in the call to SDL_RenderCopy(). Hero.DownAttackTex[Hero.CurrentFrame = SDL_GetTicks() / 200 % 3] could just as easily be Hero.DownAttackTex[SDL_GetTicks() / 200 % 3].
#2: After assigning to Hero.CurrentFrame, you increment it, but it gets re-assigned back to the same value on the next frame anyway.
#3: SDL_GetTicks() might evaluate differently on each call, sending incompatible rectangles to SDL_RenderCopy().
 
 
The least-evil, but still-flawed rewrite would be:

	if(Hero.CurrentState == Hero.ATTACK && Hero.Facing == Hero.DOWN)
	{
		Hero.CurrentFrame = SDL_GetTicks() / 200 % 3;
		SDL_RenderCopy(GameRend,Hero.DownAttackTex[Hero.CurrentFrame],NULL,&Hero.DownAttackRect[Hero.CurrentFrame]);
	}

Then you still have to fix the fact that the animation can start on any frame rather than always on the 0’th frame, and then you also have to find and fix the NULL-pointer issue.
And then you have to fix the other location(s) where you have made similar mistakes.


L. Spiro

Edited by L. Spiro

Share this post


Link to post
Share on other sites

As I mentioned in one of your previous threads, the point of using CurrentFrame = SDL_GetTicks() / 200 % 3 (or other values instead of 3) was a way to quickly/with a low amount of changes be able to help verify what was causing a bug you were having earlier. It was not suggested as a fix (explicitly so), because of various reaons, some of which have been pointed out by L. Spiro.

 

Your current problem might be caused by the contents of DownAttackTex -- we never see how this is created/filled. Possibly there's some uninitialized data here, or maybe you're accessing something out of bounds of the array.

I'd recommend setting a breakpoint at the function which makes the game crash, and look at what each variable in the function call evaluates to. This should hopefully help locate the problem.

 

That said, I'd like to reiterate both L. Spiro's and my own earlier comment. Once you've fixed this problem, you should take a closer look at how you're structuring and doing your sprites/animations. You're still fairly early in the process, which means fixing it and having a more solid foundation to work on will be very valuable and time-saving going forward.

Share this post


Link to post
Share on other sites
SDL_Surface* UpAttack[3];
	SDL_Texture* UpAttackTex[3];
	SDL_Rect UpAttackRect[3];
	SDL_Surface* DownAttack[3];
	SDL_Texture* DownAttackTex[3];
	SDL_Rect DownAttackRect[3];
	SDL_Surface* SideAttack[3];
	SDL_Texture* SideAttackTex[3];
	SDL_Rect SideAttackRect[3];


	Hero.UpAttack[0] = IMG_Load("Hero\\a1.png");
	Hero.UpAttackTex[0] = SDL_CreateTextureFromSurface(GameRend,Hero.UpAttack[0]);
	Hero.UpAttack[1] = IMG_Load("Hero\\a2.png");
	Hero.UpAttackTex[1] = SDL_CreateTextureFromSurface(GameRend,Hero.UpAttack[1]);
	Hero.UpAttack[2] = IMG_Load("Hero\\a3.png");
	Hero.UpAttackTex[2] = SDL_CreateTextureFromSurface(GameRend,Hero.UpAttack[2]);

	Hero.DownAttack[0] = IMG_Load("Hero\\a4.png");
	Hero.DownAttackTex[0] = SDL_CreateTextureFromSurface(GameRend,Hero.DownAttack[0]);
	Hero.DownAttack[1] = IMG_Load("Hero\\a5.png");
	Hero.DownAttackTex[1] = SDL_CreateTextureFromSurface(GameRend,Hero.DownAttack[1]);
	Hero.DownAttack[2] = IMG_Load("Hero\\a6.png");
	Hero.DownAttackTex[2] = SDL_CreateTextureFromSurface(GameRend,Hero.DownAttack[2]);

	Hero.SideAttack[0] = IMG_Load("Hero\\a7.png");
	Hero.SideAttackTex[0] = SDL_CreateTextureFromSurface(GameRend,Hero.SideAttack[0]);
	Hero.SideAttack[1] = IMG_Load("Hero\\a8.png");
	Hero.SideAttackTex[1] = SDL_CreateTextureFromSurface(GameRend,Hero.SideAttack[1]);
	Hero.SideAttack[2] = IMG_Load("Hero\\a9.png");
	Hero.SideAttackTex[2] = SDL_CreateTextureFromSurface(GameRend,Hero.SideAttack[2]);

Here is the loading images and texture functions for the attack images. I'll try adding break points to see what the values are, and where the game crashes. I also know I'm probably not going about this, the best way. I am trying to learn though and get better.

Share this post


Link to post
Share on other sites

This topic is 1207 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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