Search…

Hiện Thực Frame Per Second (FPS) trong SDL

27/09/20204 min read
Hướng dẫn cách hiện thực giới hạn FPS - Limit FPS với thư viện SDL.

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:

ss_1

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:

ss_2

Download demo

Stdio_SDL_FPS_VS2013.zip

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024