Post date: Jul 4, 2011 5:04:59 PM
Như đã trình bày ở trên, Limit framerate đảm bảo fps được duy trì ổn định quanh một giá trị qui ước. Giả sử mong muốn tốc độ game ổn định ở khoảng 25 fps.
25 fps <=> 40ms/frame
Như vậy, mỗi lần update & render trung bình khoảng 80 ms. Trong trường hợp tổng thời gian update + render nhỏ hơn 80ms, game được phép "ngủ" trong khoảng thời gian còn lại.
Trong hình minh họa trên:
Kỹ thuật limit fps không phải là kỹ thuật làm tăng fps. Để nâng cao fps cho game, cần kỹ thuật optimization.
Không có một giá trị cụ thể nào được đưa ra cho câu trả lời này. Tùy vào từng game, từng loại game mà người lập trình/nhà sản xuất đưa ra con số qui định cho mình. Thông thường, fps = 25 là ổn.
Tuy nhiên, việc limit fps sẽ không có tác dụng nếu fps thật sự nhỏ hơn fps cần limit. Xem ví dụ trên, frame 2. Trong trường hợp này, limit fps không có vai trò gì khi đặt ở ngưỡng 25fps. Tuy nhiên, với ngưỡng 12.5 fps (80 ms/frame), limit fps lại có tác dụng.
Bước 1: Lấy ngày giờ hệ thống
Ta cần một hàm lấy giờ hệ thống để tính toán khoảng thời gian dùng cho update + render. Để làm được điều này:
Header.h
.... #if CONFIG_PLATFORM==PLATFORM_WIN32_VS # include <windows.h> # include <time.h> #endif ....
CDevice.h
... namespace GameTutor { class CDevice { public: ... void SleepEx(unsigned long milisec); unsigned long GetTimer(); ... }; } ...
CDevice.cpp
...... unsigned long CDevice::GetTimer() { #if CONFIG_PLATFORM==PLATFORM_WIN32_VS return clock(); #else TODO("GetTimer for CONFIG_PLATFORM!=PLATFORM_WIN32_VS is not implement yet !"); return 0; #endif } ......
Bước 2: Tạo lớp CFpsManager quản lý fps
Lớp CFpsManager cũng được thiết kế dạng singleton, gồm các phương thức:
CFpscontroller.h
#ifndef __CFPSCONTROLLER_H__ #define __CFPSCONTROLLER_H__ #include "Header.h" #define DEFAULT_LIMIT_FPS 25 namespace GameTutor { class CFpsController { public: static CFpsController* GetInstance() { if (!s_pInstance) { s_pInstance = new CFpsController(); } return s_pInstance; } virtual ~CFpsController(){} void SetLimitFps(unsigned int limitFps); void BeginCounter(); void EndCounter(); int GetFrameDt() {return m_iFrameDt;} int GetRuntimeFps() {return (m_iFrameDt)?int(1000/m_iFrameDt):0;} protected: CFpsController(): m_iLimitFps(0), m_iLimitFrameDt(0), m_iStartTime(0), m_iFrameDt(0) { SetLimitFps(DEFAULT_LIMIT_FPS); } static CFpsController* s_pInstance; protected: int m_iLimitFps; int m_iLimitFrameDt; int m_iFrameDt; private: long m_iStartTime; }; } #endif
CFpsController.cpp
#include "CFpsController.h" #include "CDevice.h" namespace GameTutor { CFpsController* CFpsController::s_pInstance = 0; void CFpsController::SetLimitFps(unsigned int limitFps) { m_iLimitFps = limitFps; m_iLimitFrameDt = 1000/limitFps; } void CFpsController::BeginCounter() { m_iStartTime = CDevice::GetInstance()->GetTimer(); } void CFpsController::EndCounter() { long Endtime = CDevice::GetInstance()->GetTimer(); int Dt = int(Endtime - m_iStartTime); if (Dt < m_iLimitFrameDt) { m_iFrameDt = m_iLimitFrameDt; CDevice::GetInstance()->SleepEx(m_iLimitFrameDt - Dt); } else { m_iFrameDt = Dt; CDevice::GetInstance()->SleepEx(1); } } }
Ngoài cái chức năng chính trên, CFpsController còn có thể mở rộng, phục vụ cho việc thống kê fps.
Bước 3: Cài đặt chức năng tính toán fps vào vòng lập chính của game
Ta tiến hành hiệu chỉnh CGame
CGame.cpp
#include "CGame.h" #include "Header.h" #include "CStateManagement.h" #include "CDevice.h" #include "CFpsController.h" namespace GameTutor { ... void CGame::Run() { this->Init(); while (m_isAlived) { CFpsController::GetInstance()->BeginCounter(); if (m_isPaused) { CStateManagement::GetInstance()->Update(true); } else { CStateManagement::GetInstance()->Update(false); } CFpsController::GetInstance()->EndCounter(); } //force clean up current state CStateManagement::GetInstance()->SwitchState(0); CStateManagement::GetInstance()->Update(false); Destroy(); } }
Download