Hi all, this is my first post as a member of this forum.
I'm playing around with SDL trying to get a smooth game loop implementation working. I've attempted the fixed timestep approach as described here: http://gafferongames.com/game-physics/fix-your-timestep/.
I'm having trouble with stuttering and I'm not sure how to proceed to work out what's wrong. The update function appears to be running at the correct rate and I have tried to interpolate the remaining time in the accumulator when rendering the scene.
- MingW
- SDL 2
- Windows 7 64
- Intel integrated graphics
Stuttering occurs in both windowed and full screen and with vsync on and off (it's significantly worse with vsync off).
When moving around the screen using the arrow keys, the background can be seen to stutter regularly.
Any help with this would be much appreciated. Any examples of smooth game loops would also be appreciated.
#include <SDL.h>
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 480;
const Uint32 TIMESTEP = 16;
const int SPRITE_SIZE = 64;
const double SPRITE_VELOCITY = 300 / 1000.0;
double gPosX = 0.0;
double gPosY = 0.0;
double gPrevPosX = 0.0;
double gPrevPosY = 0.0;
double gVelocityX = 0.0;
double gVelocityY = 0.0;
SDL_Renderer* gRenderer = NULL;
void handleInput()
{
const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
gVelocityX = 0.0;
gVelocityY = 0.0;
bool leftKeyPressed = currentKeyStates[SDL_SCANCODE_LEFT];
bool rightKeyPressed = currentKeyStates[SDL_SCANCODE_RIGHT];
bool upKeyPressed = currentKeyStates[SDL_SCANCODE_UP];
bool downKeyPressed = currentKeyStates[SDL_SCANCODE_DOWN];
if(leftKeyPressed && !rightKeyPressed)
{
gVelocityX = - SPRITE_VELOCITY;
}
else if(!leftKeyPressed && rightKeyPressed)
{
gVelocityX = SPRITE_VELOCITY;
}
if(upKeyPressed && !downKeyPressed)
{
gVelocityY = - SPRITE_VELOCITY;
}
else if(!upKeyPressed && downKeyPressed)
{
gVelocityY = SPRITE_VELOCITY;
}
}
void update(const Uint32 timestep)
{
gPrevPosX = gPosX;
gPrevPosY = gPosY;
gPosX += gVelocityX * timestep;
gPosY += gVelocityY * timestep;
}
void render(SDL_Point& spritePos)
{
SDL_SetRenderDrawColor(gRenderer, 0x33, 0x33, 0x33, 0xFF);
SDL_RenderClear(gRenderer);
// Draw background
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x80, 0x80, 0xFF);
bool iEven = true;
bool jEven = true;
for (int i=0; i<100; i++)
{
for (int j=0; j<100; j++)
{
if (iEven != jEven)
{
SDL_Rect fillRect = { i * SPRITE_SIZE - spritePos.x, j * SPRITE_SIZE - spritePos.y,
SPRITE_SIZE, SPRITE_SIZE
};
SDL_RenderFillRect(gRenderer, &fillRect);
}
jEven = !jEven;
}
iEven = !iEven;
}
// Draw pink square
SDL_SetRenderDrawColor(gRenderer, 0xCC, 0xAA, 0xCC, 0xFF);
SDL_Rect fillRect = { SCREEN_WIDTH / 2.0f - SPRITE_SIZE / 2.0f, SCREEN_HEIGHT / 2.0f - SPRITE_SIZE / 2.0f,
SPRITE_SIZE, SPRITE_SIZE
};
SDL_RenderFillRect(gRenderer, &fillRect);
SDL_RenderPresent(gRenderer);
}
int main(int argc, char* args[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Game Loop", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, 0);
gRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
bool quit = false;
Uint32 accumulator = 0;
Uint32 previousTime = 0;
while (!quit)
{
SDL_Event e;
while(SDL_PollEvent(&e))
{
if(SDL_QUIT == e.type)
{
quit = true;
}
}
Uint32 currentTime = SDL_GetTicks();
Uint32 elapsedTime = currentTime - previousTime;
previousTime = currentTime;
accumulator += elapsedTime;
while (accumulator >= TIMESTEP)
{
accumulator -= TIMESTEP;
handleInput();
update(TIMESTEP);
}
float alpha = (float) accumulator / TIMESTEP;
SDL_Point spritePos = { gPosX * alpha + gPrevPosX * (1 - alpha),
gPosY * alpha + gPrevPosY * (1 - alpha)
};
render(spritePos);
}
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(window);
SDL_Quit();
}