作者littleshan (我要加入劍道社!)
看板C_and_CPP
標題Re: [問題] 多台電腦 想讓程式統一幀數
時間Fri Oct 29 11:49:23 2010
※ 引述《turtle314 (會彈吉他屌屁)》之銘言:
: 遇到的問題: (題意請描述清楚) 各位鄉民不好意思我又來了,上次PO時間的問題
: 我想有可能是因為每台電腦所算出的幀數不同而讓計數器有點差異。
: (因為連計數器兩台同時進行都會有這種問題@@,只好把問題歸咎到這)
: 希望得到的正確結果:算出每台電腦幀數後,該如何和程式更新時間做搭配,
: 讓每台電腦都是用FPS 60/s 或其他數字來做運算,應該就可以讓程式更新速度一樣。
這問題很簡單
我不知道為什麼沒人講到重點
如果要讓每台電腦固定在 FPS 60
意指固定 16.66 msec 畫出一張 frame
然而不同電腦畫出一張 frame 的速度不同
所以你要做的就是畫完一張 frame 後
使用 Sleep 暫停一小段時間
好讓畫每個 frame 所花的時間大約是 17msec
以下是使用這個方法的程式碼:
while(...){
DWORD frame_start = GetTickCount();
// game update here
updateGame();
render();
...
// calculate spent time
DWORD spent_msec = GetTickCount() - frame_start;
// sleep until 17msec is used
if(spent_msec < 17)
Sleep(17 - spent_msec);
}
但是呢,這樣做並不是好方法
首先一個技術上的問題是 GetTickCount 誤差約在 10msec~16msec 左右 (from MSDN)
這和我們要求每張 frame 間隔 17msec 相比,實在是太大的誤差。
上面的問題可以用 QueryPerformanceCounter 來解決
不過我們會面臨另一個問題:如果有些人電腦就是太慢
導至它們每張 frame 的處理時間會超過 17msec 呢?
也許我們可以改成固定 30 frame/sec
但目前的遊戲大部份不是這樣處理的 (同樣地,跑不到30fps的人也會產生問題)
而是採用不固定 fps 的方式
把「畫出上一張 frame 的時間」傳進 gameUpdate 當中
也就是像這樣:
DWORD spent_msec = 0;
while(...){
DWORD frame_start = GetTickCount();
updateGame(spent_msec);
render();
spent_msec = GetTickCount() - frame_start;
}
而在 updateGame 中要跟據上一張 frame 花的時間
去更新遊戲中各元件 (以你的例子來說就是音符) 的位置
void updateGame(DWORD spent_msec)
{
// 計算音符的位置
// 新位置 = 舊位置 + 音符速度 * 時間
note.position += note.velocity * 0.001 * spent_msec;
// ...
}
理論上用 QueryPerformanceCounter 會好一點 但使用起來會有一些其它考量
(在多核心 CPU 上,BIOS 的 bug 可能會導致它回傳意料外的結果,詳見 MSDN)
簡單起見我還是用 GetTickCount 來示範
以上.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.32.15.163
推 yauhh:水 10/29 12:00
→ final01:在real time的書裡學過 ? 10/29 12:22
→ wendly777:使用timeBeginPeriod(1),timeGetTime()的誤差會小於1ms 10/29 14:28
→ wendly777:QueryPerformanceCounter是用來算需求遠小於1ms的情況 10/29 14:29
→ littleshan:感謝樓上補充 10/29 14:58
推 VictorTom:推:) 10/29 15:47