Skip to main content
removed my previous edit
Source Link
user9266
  • 111
  • 1
  • 7

Edit: I resolved the issue.

The steps I have taken are:

  1. Getting rid of SDL_GetSleep()
  2. Implementing a framerate cap via putting an if statement within the game loop. Then, accumulating the seconds until I reach the cycle time I need e.g. 16 ms. (Do not forget to reset the accumulator inside the if block. It needs to recount to the 16 ms every time.)
  3. Doing the movement/motion via LERP (linear interpolation). I am not sure how that exactly works or what it is, but it basically tells you at what rate you need to update a value (velocity, displacement etc.) to make it run smooth as butter.

Below is the code. I made some changes here and there.

This is my Clock struct/class that helps me to retrieve the difference in seconds (delta time):

    struct Clock
{
    Uint64 previous_ticks{};
    float elapsed_seconds{};

    void tick()
    {
        const Uint64 current_ticks{ SDL_GetPerformanceCounter() };
        const Uint64 delta{ current_ticks - previous_ticks };
        previous_ticks = current_ticks;
        static const Uint64 TICKS_PER_SECOND{ SDL_GetPerformanceFrequency() };
        elapsed_seconds = delta / static_cast<float>(TICKS_PER_SECOND);
    }
};

static inline float lerp(const float t_end, const float t_start, const float t_dt)
{
    return  (t_end - t_start) * t_dt + t_start;
}



And this is how my loop looks like:

int main()

{ // Intialize SDL2 SDL_Init(SDL_INIT_EVERYTHING);

// Defining world & window dimensions and camera position
const int SCREEN_WIDTH{ 800 };
const int SCREEN_HEIGHT{ 600 };

// Create window and default rendering context
SdlCreateWindowAndRendererWrapped wr{ SCREEN_WIDTH, SCREEN_HEIGHT };
SDL_Renderer * const ren{ &wr.get_resource_renderer() };

Object ground(ren, "assets/ground.png", 0, 0, 95);
ground.set_size(600);
ground.pos.x = 200;
ground.pos.y = 200;

Object bot(ren, "assets/bot.png", 40, 46, 32);
bot.set_size(200);

/*--------------Game loop--------------*/
bool is_running{ true };
SDL_Event event{};
SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
// Timing constants
const int UPDATE_FREQUENCY{ 60 };
const float CYCLE_TIME{ 1.0f / UPDATE_FREQUENCY };
// System timing
static Clock system_clock;
float accumulated_seconds{ 0.0f };
while (is_running)
{
    // Update clock
    system_clock.tick();
    accumulated_seconds += system_clock.elapsed_seconds;

    /*--------------Event loop--------------*/
    while (SDL_PollEvent(&event))
    {
        if (event.type == SDL_QUIT)
        {
            is_running = false;
        }
        else if (event.type == SDL_KEYDOWN)
        {
            switch (event.key.keysym.sym)
            {
            case SDLK_UP:
            {
                bot.velocity.y = -1.0f;
            }
            break;
            case SDLK_DOWN:
            {
                bot.velocity.y = 1.0f;
            }
            break;
            case SDLK_LEFT:
            {
                bot.velocity.x = -1.0f;
            }
            break;
            case SDLK_RIGHT:
            {
                bot.velocity.x = 1.0f;
            }
            break;
            default:
            { }
            break;
            }
        }
        else if (event.type == SDL_KEYUP)
        {
            switch (event.key.keysym.sym)
            {
            case SDLK_UP:
            {
                bot.velocity.y = 0.0f;
            }
            break;
            case SDLK_DOWN:
            {
                bot.velocity.y = 0.0f;
            }
            break;
            case SDLK_LEFT:
            {
                bot.velocity.x = 0.0f;
            }
            break;
            case SDLK_RIGHT:
            {
                bot.velocity.x = 0.0f;
            }
            break;
            default:
            { }
            break;
            }
        }
    }

    // Cap the framerate
    if (std::isgreater(accumulated_seconds, CYCLE_TIME))
    {
        // Reset the accumulator
        accumulated_seconds = 0.0f;

        /*--------------Physics loop--------------*/
        static Clock clock;
        clock.tick();

        float lerped_v = lerp(20, 0, clock.elapsed_seconds * 1000);

        bot.pos.x += bot.velocity.x * lerped_v * clock.elapsed_seconds;
        bot.pos.y += bot.velocity.y * lerped_v * clock.elapsed_seconds;

        ground.update();
        bot.update();

        /*--------------Rendering loop--------------*/
        SDL_RenderClear(ren);
        ground.draw(ren);
        bot.draw(ren);
        SDL_RenderPresent(ren);

        /*--------------Todo: Animation loop--------------*/
    }
}

// Clean up used resources
SDL_Quit();
return 0;

}

Note that I made some changes in the Object struct/class from above. I removed the getters and setters and made the position vector public to make the calculations a bit more comfortable.
Also I removed some code to help me focus more at the issue at hand.

This is the result:

https://i.imgur.com/7LWUvD1.gif

Hope that helps! :)

Addendum: You don't need LERP. It was as Alexandre Vaillancourt suggested due to rounding errors.

Edit: I resolved the issue.

The steps I have taken are:

  1. Getting rid of SDL_GetSleep()
  2. Implementing a framerate cap via putting an if statement within the game loop. Then, accumulating the seconds until I reach the cycle time I need e.g. 16 ms. (Do not forget to reset the accumulator inside the if block. It needs to recount to the 16 ms every time.)
  3. Doing the movement/motion via LERP (linear interpolation). I am not sure how that exactly works or what it is, but it basically tells you at what rate you need to update a value (velocity, displacement etc.) to make it run smooth as butter.

Below is the code. I made some changes here and there.

This is my Clock struct/class that helps me to retrieve the difference in seconds (delta time):

    struct Clock
{
    Uint64 previous_ticks{};
    float elapsed_seconds{};

    void tick()
    {
        const Uint64 current_ticks{ SDL_GetPerformanceCounter() };
        const Uint64 delta{ current_ticks - previous_ticks };
        previous_ticks = current_ticks;
        static const Uint64 TICKS_PER_SECOND{ SDL_GetPerformanceFrequency() };
        elapsed_seconds = delta / static_cast<float>(TICKS_PER_SECOND);
    }
};

static inline float lerp(const float t_end, const float t_start, const float t_dt)
{
    return  (t_end - t_start) * t_dt + t_start;
}



And this is how my loop looks like:

int main()

{ // Intialize SDL2 SDL_Init(SDL_INIT_EVERYTHING);

// Defining world & window dimensions and camera position
const int SCREEN_WIDTH{ 800 };
const int SCREEN_HEIGHT{ 600 };

// Create window and default rendering context
SdlCreateWindowAndRendererWrapped wr{ SCREEN_WIDTH, SCREEN_HEIGHT };
SDL_Renderer * const ren{ &wr.get_resource_renderer() };

Object ground(ren, "assets/ground.png", 0, 0, 95);
ground.set_size(600);
ground.pos.x = 200;
ground.pos.y = 200;

Object bot(ren, "assets/bot.png", 40, 46, 32);
bot.set_size(200);

/*--------------Game loop--------------*/
bool is_running{ true };
SDL_Event event{};
SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
// Timing constants
const int UPDATE_FREQUENCY{ 60 };
const float CYCLE_TIME{ 1.0f / UPDATE_FREQUENCY };
// System timing
static Clock system_clock;
float accumulated_seconds{ 0.0f };
while (is_running)
{
    // Update clock
    system_clock.tick();
    accumulated_seconds += system_clock.elapsed_seconds;

    /*--------------Event loop--------------*/
    while (SDL_PollEvent(&event))
    {
        if (event.type == SDL_QUIT)
        {
            is_running = false;
        }
        else if (event.type == SDL_KEYDOWN)
        {
            switch (event.key.keysym.sym)
            {
            case SDLK_UP:
            {
                bot.velocity.y = -1.0f;
            }
            break;
            case SDLK_DOWN:
            {
                bot.velocity.y = 1.0f;
            }
            break;
            case SDLK_LEFT:
            {
                bot.velocity.x = -1.0f;
            }
            break;
            case SDLK_RIGHT:
            {
                bot.velocity.x = 1.0f;
            }
            break;
            default:
            { }
            break;
            }
        }
        else if (event.type == SDL_KEYUP)
        {
            switch (event.key.keysym.sym)
            {
            case SDLK_UP:
            {
                bot.velocity.y = 0.0f;
            }
            break;
            case SDLK_DOWN:
            {
                bot.velocity.y = 0.0f;
            }
            break;
            case SDLK_LEFT:
            {
                bot.velocity.x = 0.0f;
            }
            break;
            case SDLK_RIGHT:
            {
                bot.velocity.x = 0.0f;
            }
            break;
            default:
            { }
            break;
            }
        }
    }

    // Cap the framerate
    if (std::isgreater(accumulated_seconds, CYCLE_TIME))
    {
        // Reset the accumulator
        accumulated_seconds = 0.0f;

        /*--------------Physics loop--------------*/
        static Clock clock;
        clock.tick();

        float lerped_v = lerp(20, 0, clock.elapsed_seconds * 1000);

        bot.pos.x += bot.velocity.x * lerped_v * clock.elapsed_seconds;
        bot.pos.y += bot.velocity.y * lerped_v * clock.elapsed_seconds;

        ground.update();
        bot.update();

        /*--------------Rendering loop--------------*/
        SDL_RenderClear(ren);
        ground.draw(ren);
        bot.draw(ren);
        SDL_RenderPresent(ren);

        /*--------------Todo: Animation loop--------------*/
    }
}

// Clean up used resources
SDL_Quit();
return 0;

}

Note that I made some changes in the Object struct/class from above. I removed the getters and setters and made the position vector public to make the calculations a bit more comfortable.
Also I removed some code to help me focus more at the issue at hand.

This is the result:

https://i.imgur.com/7LWUvD1.gif

Hope that helps! :)

Addendum: You don't need LERP. It was as Alexandre Vaillancourt suggested due to rounding errors.

added 97 characters in body
Source Link
user9266
  • 111
  • 1
  • 7

Addendum: You don't need LERP. It was as Alexandre Vaillancourt suggested due to rounding errors.

Addendum: You don't need LERP. It was as Alexandre Vaillancourt suggested due to rounding errors.

solved the issue
Source Link
user9266
  • 111
  • 1
  • 7
Loading
grammar
Source Link
user9266
  • 111
  • 1
  • 7
Loading
Fixed the code display, uploaded the code into the question to avoid link rot.
Source Link
Vaillancourt
  • 16.4k
  • 17
  • 55
  • 61
Loading
Source Link
user9266
  • 111
  • 1
  • 7
Loading