I have a basic implementation of SDL2 and Box2D with a ball bouncing inside of a box. Ball movement is occasionally jittery. After a couple of days of debugging, I still can't figure out what's wrong.
Here are my constants:
const float HALF = 0.5f;
const float DOUBLE = 2.0f;
const float INVERT = -1.0f;
const float FRAMES_PER_SECOND = 60.0f;
const int PHYSICS_POSITION_ITERATIONS = 8;
const int PHYSICS_VELOCITY_ITERATIONS = 12;
const float WORLD_UNIT = 2.0f;
const float WORLD_WIDTH = 80.0f;
const float WORLD_HEIGHT = 60.0f;
const float WORLD_TIME_RESOLUTION = 1.0f / FRAMES_PER_SECOND;
const float WORLD_TIME_ELAPSED_ZERO = 0.0f;
const float WORLD_GRAVITY_ZERO = 0.0f;
const float WORLD_SLOW_MOTION_FACTOR = 10.0f;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const float PIXELS_PER_METER_X = SCREEN_WIDTH / WORLD_WIDTH;
const float PIXELS_PER_METER_Y = SCREEN_HEIGHT / WORLD_HEIGHT;
const float BODY_DENSITY_PERFECT_SOLID = 1.0f;
const float BODY_RESTITUTION_PERFECT_BOUNCE = 1.0f;
const float BODY_ROTATION_ZERO = 0.0f;
const float BODY_FRICTION_ZERO = 0.0f;
const float BODY_DAMPING_ZERO = 0.0f;
const float BODY_MASS_ZERO = 0.0f;
const float BALL_RADIUS = WORLD_UNIT * HALF;
const float BALL_START_POSITION_X = 4.0f;
const float BALL_START_POSITION_Y = -30.0f;
const float BALL_START_VELOCITY_X = 40.0f;
const float BALL_START_VELOCITY_Y = 0.0f;
Here are my Box2D world and ball instantiations:
b2Vec2* gravity = new b2Vec2(WORLD_GRAVITY_ZERO, WORLD_GRAVITY_ZERO);
b2World* world = new b2World(*gravity);
world->SetContinuousPhysics(true);
b2BodyDef* ballBodyDef = new b2BodyDef();
ballBodyDef->type = b2_dynamicBody;
ballBodyDef->position.Set(BALL_START_POSITION_X, BALL_START_POSITION_Y);
ballBodyDef->linearVelocity.Set(BALL_START_VELOCITY_X, BALL_START_VELOCITY_Y);
b2MassData* ballBodyMassData = new b2MassData();
ballBodyMassData->mass = BODY_MASS_ZERO;
b2Body* ballBody = world->CreateBody(ballBodyDef);
ballBody->SetBullet(true);
ballBody->SetMassData(ballBodyMassData);
ballBody->SetLinearDamping(BODY_DAMPING_ZERO);
b2CircleShape* ballFixtureShape = new b2CircleShape();
ballFixtureShape->m_radius = BALL_RADIUS;
b2FixtureDef* ballFixtureDef = new b2FixtureDef();
ballFixtureDef->shape = ballFixtureShape;
ballFixtureDef->density = BODY_DENSITY_PERFECT_SOLID;
ballFixtureDef->restitution = BODY_RESTITUTION_PERFECT_BOUNCE;
ballFixtureDef->friction = BODY_FRICTION_ZERO;
b2Fixture* ballFixture = ballBody->CreateFixture(ballFixtureDef);
Here is my SDL2 ball sprite instantiation:
float ballShapeRadius = ballBody->GetFixtureList()[0].GetShape()->m_radius;
SDL_Rect* ballSprite = new SDL_Rect();
ballSprite->x = ballBody->GetPosition().x * PIXELS_PER_METER_X;
ballSprite->y = ballBody->GetPosition().y * PIXELS_PER_METER_Y * INVERT;
ballSprite->w = (int)(ballShapeRadius * DOUBLE * PIXELS_PER_METER_X);
ballSprite->h = (int)(ballShapeRadius * DOUBLE * PIXELS_PER_METER_Y);
Here are my SDL2 window and renderer instantiations:
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Could not initialize display: %s\n", SDL_GetError());
return 1;
}
SDL_Window* window = SDL_CreateWindow(
"TV Tennis",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_SHOWN
);
if (window == nullptr) {
fprintf(stderr, "Could not create window: %s\n", SDL_GetError());
return 1;
}
SDL_Renderer* renderTarget = SDL_CreateRenderer(
window,
-1,
SDL_RENDERER_SOFTWARE
);
if (renderTarget == nullptr) {
fprintf(stderr, "Could not create renderer: %s\n", SDL_GetError());
return 1;
}
Here is my clock instantiation and event loop:
std::chrono::steady_clock clock;
float deltaTime = WORLD_TIME_ELAPSED_ZERO;
std::chrono::_V2::steady_clock::time_point lastTick = clock.now();
std::chrono::_V2::steady_clock::time_point thisTick;
//Initialize Input
const Uint8* keyState;
SDL_Event event;
// //Enter Game Loop
bool quitFlag = false;
while ( quitFlag == false ){
thisTick = clock.now();
std::chrono::duration<float> timeElapsedSinceLastTick = thisTick - lastTick;
deltaTime += timeElapsedSinceLastTick.count();
lastTick = thisTick;
while ( deltaTime >= WORLD_TIME_RESOLUTION ){
while ( SDL_PollEvent(&event) ){
switch ( event.type ){
case SDL_QUIT:
quitFlag = true;
break;
case SDL_KEYDOWN:
if ( event.key.keysym.sym == SDLK_ESCAPE ){
quitFlag = true;
}
break;
}
world->Step( deltaTime, PHYSICS_VELOCITY_ITERATIONS,
PHYSICS_POSITION_ITERATIONS );
ballSprite->x = (int)((ballBody->GetPosition().x - ballBody->GetFixtureList()[0].GetShape()->m_radius) * PIXELS_PER_METER_X);
ballSprite->y = ((int)((ballBody->GetPosition().y + ballBody->GetFixtureList()[0].GetShape()->m_radius) * PIXELS_PER_METER_Y)) * INVERT;
deltaTime -= WORLD_TIME_RESOLUTION;
}
//Render Here
}
Any help would be greatly appreciated.