Nội dung bài viết
Đăng ký học lập trình C++
Tại STDIO bạn được dạy nền tảng lập trình tốt nhất.
Đăng ký học
Nguyễn Nghĩa Frame Per Second (FPS) là một khái niệm khá phổ biến trong game nó có ý nghĩa là số frame trên 1 giây mà máy tính có thể render, FPS càng cao thì thể hiện độ mượt của game càng cao. Với những engine như Unity hay Cocos2dx thì những engine đó đã hiện thực FPS sẵn. Trong bài viết này tôi sẽ hướng dẫn các bạn hiện thực lại FPS với thư viện SDL ở mức độ cơ bản.

Giới thiệu

Frame Per Second (FPS) là một khái niệm khá phổ biến trong game nó có ý nghĩa là số frame trên 1 giây mà máy tính có thể render, FPS càng cao thì thể hiện độ mượt của game càng cao. Với những engine như Unity hay Cocos2dx thì những engine đó đã hiện thực FPS sẵn. Trong bài viết này tôi sẽ hướng dẫn các bạn hiện thực lại FPS với thư viện SDL ở mức độ cơ bản.

Tiền đề bài viết

Tiếp nối những bài viết hướng dẫn lập trình với framework SDL (Simple DirectMedia Layer).

Trong bài viết tôi sẽ sử dụng FPS thay vì Frame Per Second.

Đối tượng hướng đến

Những lập trình viên đã có kiến thức vững chắc về ngôn ngữ lập trình C++, mong muốn tìm hiểu và hiện thực lại FPS sử dụng thư viện SDL.

Ý tưởng

Ta có đ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

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. Chúng ta thấy frame được vẽ ra quá nhanh, không thể biết được là bao nhiêu frame/second.

Ý tưởng đặt ra là chúng ta sẽ 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à chúng ta cần render trên 1 giây. Ở đây tôi sẽ gán FPS = 60.

DELAY_TIME  = 1000 milisecond/FPS, chính 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.

const int FPS = 60;
const int DELAY_TIME = 1000 / 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 ta 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 thì chúng ta lấy thời gian bắt đầu của 1 frame, sau khi tính toán và render xong, ta 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

 

THẢO LUẬN
ĐÓNG