Frame Per Second (FPS) là một khái niệm khá phổ biến trong game, nó tượng trưng cho số frame trên 1 giây mà máy tính có thể render, FPS càng cao thể hiện độ mượt của game càng cao.
Ý tưởng
Với đoạn mã như dưới đây:
#include <stdio.h> #include <SDL.h> #undef main int main() { SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; bool isRunning = true; SDL_Event mainEvent; int x = 0; //initializes the subsystems if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { printf("Unable to initialize SDL %s\n", SDL_GetError()); return -1; } //Create window window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN); if (window == NULL) { printf("Could not create window %s", SDL_GetError()); return -1; } //create a renderer renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { printf("Could not create render %s", SDL_GetError()); return -1; } //set background color SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); //main loop while (isRunning) { //main event while (SDL_PollEvent(&mainEvent)) { switch (mainEvent.type) { //User - requested quit case SDL_QUIT: { isRunning = false; break; } default: { break; } } } // clear the window to black SDL_RenderClear(renderer); //draw in here SDL_Log("Frame :%d", x++); //draw to screen SDL_RenderPresent(renderer); } //Destroy a window. SDL_DestroyWindow(window); //Destroy a renderer SDL_DestroyRenderer(renderer); //cleans up all initialized subsystems SDL_Quit(); return 0; }
Kết quả chạy chương trình:
Limit FPS - giới hạn frame rate
Giả sử ở đây là mỗi lần biến x
được in ra thì xem như một frame được vẽ lên màn hình, frame được vẽ ra quá nhanh, không thể biết được là bao nhiêu frame/second.
Ý tưởng là xác định và kiểm soát số frame được render trên 1 giây bằng cách:
Gọi:
FPS
là số frame mà cần render trên 1 giây. Gán:const int FPS = 60;
DELAY_TIME
là thời gian tính trên lý thuyết để máy tính tính toán và render xong 1 frame. Như vậy mỗi frame sẽ cần khoảng 16 miliseconds để có thể tính toán và render lên màn hình. Gán:const int DELAY_TIME = 1000 / FPS;
( 1000 milisecond/FPS)frameStart
là thời gian bắt đầu của 1 frame;frameTime
là thời gian thực sự để máy tính tính toán và render xong 1 frame kể từ thời điểm bắt đầu.
Kiểm tra nếu frameTime < DELAY_TIME
thì delay một khoảng thời gian bằng đúng DELAY_TIME - frameTime
, nghĩa là nếu máy tính tính toán và render xong 1 frame nhanh hơn số thời gian lý thuyết cần cho 1 frame nên phải delay khoảng thời gian còn lại.
Hiện thực
#include <stdio.h> #include <SDL.h> #undef main int main() { SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; bool isRunning = true; SDL_Event mainEvent; int x = 0; const int FPS = 60; const int DELAY_TIME = 1000 / FPS; Uint32 frameStart; Uint32 frameTime; //initializes the subsystems if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { printf("Unable to initialize SDL %s\n", SDL_GetError()); return -1; } //Create window window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN); if (window == NULL) { printf("Could not create window %s", SDL_GetError()); return -1; } //create a renderer renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { printf("Could not create render %s", SDL_GetError()); return -1; } //set background color SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); //main loop while (isRunning) { frameStart = SDL_GetTicks(); //main event while (SDL_PollEvent(&mainEvent)) { switch (mainEvent.type) { //User - requested quit case SDL_QUIT: { isRunning = false; break; } default: { break; } } } // clear the window to black SDL_RenderClear(renderer); //draw in here SDL_Log("Frame :%d", x++); //draw to screen SDL_RenderPresent(renderer); frameTime = SDL_GetTicks() - frameStart; if (frameTime < DELAY_TIME) { SDL_Delay(DELAY_TIME - frameTime); } } //Destroy a window. SDL_DestroyWindow(window); //Destroy a renderer SDL_DestroyRenderer(renderer); //cleans up all initialized subsystems SDL_Quit(); return 0; }
Hàm SDL_GetTicks()
có chức năng lấy về tổng số miliseconds từ khi SDL được khởi tạo.
Với mỗi vòng lặp, lấy thời gian bắt đầu của 1 frame, sau khi tính toán và render xong, lấy tiếp thời gian mà máy tính đã tính toán và render xong 1 frame, kiểm tra điều kiện, nếu thỏa mãn sẽ delay số miliseconds còn lại (DELAY_TIME - frameTime
) sau đó mới bắt đầu sang frame tiếp theo.
Kết quả sau khi chạy chương trình: