I am experiencing stutter when I am moving faster than 0.1 units in my program. [![jittery motion on 0.3 units][1]][1] When doing exactly 0.1 units I get: [![smooth motion on 0.1][2]][2] [1]: https://i.sstatic.net/8Sd6y.gif [2]: https://i.sstatic.net/Wsh4v.gif For test purposes I've made the bot always heading southeast. 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{ 480 }; const int WORLD_WIDTH{ 1000 }; const int WORLD_HEIGHT{ 1000 }; int view_x{ 0 }; int view_y{ 0 }; // 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.set_pos(200, 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); while (is_running) { Uint64 start = SDL_GetPerformanceCounter(); /*--------------Event loop--------------*/ while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { is_running = false; } } // end of the event loop /*--------------Physics loop--------------*/ static Clock clock; clock.tick(); Vec2f v{ 0.3f, 0.3f }; bot.move(v, clock.delta); // Screen coordinate translations bot.set_pos(bot.get_pos().x - view_x, bot.get_pos().y - view_y); ground.set_pos(ground.get_pos().x - view_x, ground.get_pos().y - view_y); ground.update(); bot.update(); // Check camera bounds if (view_x < 0) { view_x = 0; } if (view_y < 0) { view_y = 0; } if (view_x > WORLD_WIDTH - SCREEN_WIDTH) { view_x = WORLD_WIDTH - SCREEN_WIDTH; } if (view_y > WORLD_HEIGHT - SCREEN_HEIGHT) { view_y = WORLD_HEIGHT - SCREEN_HEIGHT; } // Make the camera follow the bot view_x = bot.get_pos().x - SCREEN_WIDTH / 2; view_y = bot.get_pos().y - SCREEN_HEIGHT / 2; /*--------------Rendering loop--------------*/ SDL_RenderClear(ren); ground.draw(ren); bot.draw(ren); SDL_RenderPresent(ren); /*--------------Todo: Animation loop--------------*/ // Cap to 60 FPS (approx. 16.666 ms per frame -- the cycle time) Uint64 end = SDL_GetPerformanceCounter(); float elapsed_ms{ (end - start) / static_cast<float>(SDL_GetPerformanceFrequency()) * 1000.0f }; if (std::isless(elapsed_ms, 16.666f)) { SDL_Delay(static_cast<int>(floorf(16.666f - elapsed_ms))); } } // Clean up used resources SDL_Quit(); return 0; } I took inspiration for designing my game loop from https://thenumbat.github.io/cpp-course/sdl2/08/08.html The Clock class/struct was implemented exactly as Salajouni's one: https://gamedev.stackexchange.com/questions/110825/how-to-calculate-delta-time-with-sdl The camera was implemented via this method: https://wiki.allegro.cc/index.php?title=How_to_implement_a_camera This is how my Object struct/class looks like: class Object { public: explicit Object(SDL_Renderer * t_renderer, const std::string & t_s, const int t_x, const int t_y, const int t_sz) { sprite = new Sprite; sprite->set_texture(t_renderer, t_s); sprite->set_src_rect(t_x, t_y, t_sz, t_sz); sprite->set_dest_rect(0, 0, t_sz, t_sz); size = t_sz; } ~Object() { delete sprite; sprite = nullptr; } int get_size() const { return size; } void set_size(const int t_sz) { size = t_sz; } const Vec2i & get_pos() const { return pos; } void set_pos(const int t_x, const int t_y) { pos.x = t_x; pos.y = t_y; } void move(const Vec2f & t_v, const Uint32 t_delta) { pos.x += static_cast<int>(t_v.x * t_delta); pos.y += static_cast<int>(t_v.y * t_delta); } // Todo: void animate() { } void update() { sprite->set_dest_rect(pos.x, pos.y, size, size); } void draw(SDL_Renderer * ren) { SDL_RenderCopy(ren, &sprite->get_texture(), &sprite->get_src_rect(), &sprite->get_dest_rect()); } private: Sprite * sprite{}; Vec2i pos{}; int size{}; }; The part that supposedly needs the most attention is the **physics loop**. This is the part where all the motion and motion updates happen. In there I define a velocity vector and set both of its components too 0.3. After that the stutter/jitter happens. However, when I do 0.1, then it runs smoothly as shown in the pictures above. I created the window via SDL_CreateWindowAndRenderer(). So accelerated rendering should be active. I am not sure whether or not VSYNC gets activated as well when doing SDL_CreateWindowAndRenderer(). So what could possibly be the cause? Is it due to cascading rounding errors? Is it due to the active VSYNC and the manual framerate cap at the end of the loop? What is it exactly that is causing the stutter? PS: And for the possibility that my Vector2 template class needs attention as well, there you go: /* 2D math classes */ namespace oki2d::math2d { // Vector2 class definition template <typename T> struct Vector2 { public: T x{}; T y{}; explicit Vector2() : x{}, y{} { } explicit Vector2(T t_value) : x{ t_value }, y{ t_value } { } explicit Vector2(const T t_x, const T t_y) : x{ t_x }, y{ t_y } { } explicit Vector2(const Vector2 & t_v) : x{ t_v.x }, y{ t_v.y } { } Vector2 & operator=(const Vector2 & t_rhs) { if (&t_rhs == this) { return *this; } x{ t_rhs.x }; y{ t_rhs.y }; return *this; } Vector2 operator-() const { return Vector2{ -x, -y }; } bool operator==(const Vector2 & t_rhs) const { // Perform single-precision floating-point comparison (float) if (std::is_floating_point<T>::value) { return (std::fabsf(static_cast<float>((*this).x - t_rhs.x)) < std::numeric_limits<float>::epsilon()) && (std::fabsf(static_cast<float>((*this).y - t_rhs.y)) < std::numeric_limits<float>::epsilon()); } assert(std::is_floating_point<T>::value == false); // Perform integer comparison otherwise return x == t_rhs.x && y == t_rhs.y; } bool operator!=(const Vector2 & t_rhs) const { return !((*this) == t_rhs); } const Vector2 & operator+=(const Vector2 & t_rhs) { if (&t_rhs == this) { return *this; } x += t_rhs.x; y += t_rhs.y; return *this; } Vector2 & operator-=(const Vector2 & t_rhs) const { if (&t_rhs == this) { return *this; } x -= t_rhs.x; y -= t_rhs.y; return *this; } Vector2 operator+(const Vector2 & t_rhs) const { return Vector2{ x + t_rhs.x, y + t_rhs.y }; } Vector2 operator-(const Vector2 & t_rhs) const { return Vector2{ x - t_rhs.x, y - t_rhs.y }; } Vector2 operator*(const T t_rhs) const { return Vector2{ x * t_rhs, y * t_rhs }; } Vector2 operator/(const T t_rhs) const { return Vector2{ x / t_rhs, y / t_rhs }; } static T double_length(const Vector2 & t_v) { return t_v.x * t_v.x + t_v.y * t_v.y; } static T length(const Vector2 & t_v) { return std::sqrt(t_v.x * t_v.x + t_v.y * t_v.y); } static Vector2 normalize(const Vector2 & t_v) { const T len{ length(t_v) }; return Vector2{ t_v.x / len, t_v.y / len }; } static T dot_product(const Vector2 & t_lhs, const Vector2 & t_rhs) { return t_lhs.x * t_rhs.x + t_lhs.y * t_rhs.y; } friend std::ostream & operator<<(std::ostream & t_os, const Vector2 & t_v) { t_os << "(" << t_v.x << ", " << t_v.y << ")"; return t_os; } }; // Vector2 // Using declarations using Vec2i = Vector2<int>; using Vec2f = Vector2<float>; } // oki2d::math2d It is just a simple templated 2D vector math class. Nothing scary. Edit: I resolved the issue. The steps I have taken are: 1) Getting rid of SDL_GetSleep() <br> 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.) <br> 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. <br> Below is the code. I made some changes here and there. <br><br> 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; } <br><br> 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. <br> Also I removed some code to help me focus more at the issue at hand. <br><br> This is the result: https://i.imgur.com/7LWUvD1.gif Hope that helps! :)