У меня проблема с анимацией в SDL 2. Я попробовал два возможных решения для ограничения частоты кадров:
один использует постоянный сон 16 мс (только для тестирования), а другой использует таймер для более точного ограничения кадра ( runGameLoop_computed функция игрового цикла).
В целях тестирования я просто рисую и перемещаю прямоугольник с помощью функции SDL_RenderFillRect , но оба метода игрового цикла создают дрожание при движении прямоугольника.
Есть ли у вас представление о том, что здесь не так, и анимация не плавная?
Полный код:
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <thread>
#include <math.h>
using namespace std;
//sdl window and window renderer pointers
static SDL_Window *gWindow;
static SDL_Renderer *windowRenderer;
//terminates the app when users closes the window
static bool exitAppFlag = false;
static int window_width = 1000;
static double position_x = 0; // current x position to draw the rectangle
static double delta_time = 0; // the time passed since last draw
//initilizes SDL and displays the application window
void initSDL()
{
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
}
else
{
printf( "SDL ok \n");
//Create window
gWindow = SDL_CreateWindow( "Tank Multiplayer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, 500, SDL_WINDOW_SHOWN);
if( gWindow == nullptr )
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
}
else
{
//Create renderer for window
windowRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED);
//windowRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_SOFTWARE);
if(windowRenderer == nullptr )
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor(windowRenderer, 0, 0, 255, 255);
//SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x00 );
}
} //SDL_CreateWindow
}
}
//part of game loop: processes events (currently handles only window close event)
void processEvents()
{
SDL_Event p_event;
while (SDL_PollEvent(&p_event) != 0){
if (p_event.type == SDL_EventType::SDL_QUIT){
//if the user closed the window, then set the flag to true, so that we can exit the application
exitAppFlag = true;
return;
}
}
}
//part of game loop: updates the position_x variable based on the time passed since the last time (delta_time)
void update()
{
static double speed = 0.0532;
position_x += delta_time * speed;
if (position_x > window_width) position_x = 0;
}
//part of game loop: draws the rectange to the screen
void draw()
{
SDL_Rect r;
r.h = 300;
r.w = 100;
r.x = static_cast<int>(round(position_x));
r.y = 0;
SDL_SetRenderDrawColor(windowRenderer, 0x00, 0x00, 0x00, 0x00 );
SDL_RenderClear(windowRenderer);
SDL_SetRenderDrawColor(windowRenderer, 0, 0, 255, 255);
SDL_RenderFillRect(windowRenderer, &r);
SDL_RenderPresent(windowRenderer);
}
//game loop: frame capping based on the given fps
void runGameLoop_computed()
{
static double fps = 60;
static double single_frame_time_micro = (1000 / fps) * 1000;
std::chrono::time_point<std::chrono::high_resolution_clock>begin_time_point = std::chrono::high_resolution_clock::now();//stores the time point before processing game objects and drawing
long long delta_time_micro = 0;
while (!exitAppFlag) {
delta_time_micro = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - begin_time_point).count();
if (delta_time_micro < single_frame_time_micro){
std::this_thread::sleep_for(std::chrono::microseconds(static_cast<long long>(single_frame_time_micro - delta_time_micro)));
delta_time_micro = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - begin_time_point).count();
}
delta_time = delta_time_micro / 1000.00;
//std::cout << delta_time << std::endl;
begin_time_point = std::chrono::high_resolution_clock::now();//stores the time point before processing game objects and drawing
processEvents();
update();
draw();
}
}
//game loop: constant sleep time 16 ms, almost 60fps
void runGameLoop_static()
{
delta_time = 16.0;
while (!exitAppFlag) {
SDL_Delay(16);
processEvents();
update();
draw();
}
}
int main()
{
//initilize SDL library and create window
initSDL();
//enter game loop
//runGameLoop_static(); //constant sleep time 16ms
runGameLoop_computed(); //frame capping based on given fps
return 0;
}
Внутри основной функции вы можете раскомментировать способ тестирования:
runGameLoop_static
или же
runGameLoop_computed
Я загрузил полный проект Qt здесь (macOS): https://www.sendspace.com/file/1p4oqq