2008/02/24(日)autoFPS フレームスキップ モジュール
ゲーム向け?の言語のくせに、フレームスキップとかやってくれる命令ないですよね。
await は半端だし、フレームスキップの処理とか割とFAQなんじゃないのかな。
HSPで解説してるとこあまり見ないなぁ。
まぁ、DirectXとか使えば、その辺勝手にやってくれるし、標準命令でゲーム作る人あまりいないのかも。
まぁ、元々標準命令でゲーム作るんなら速度は出ないし、そんなもん気にしないで済むように作れってことなんだろうなぁ。
まぁいいや、とりあえずモジュール化しちゃえ。
このモジュールはスクリプトに組み込んで自由に使用できます。
標準命令を使ったゲームにおいて重い処理とは主に描画です。
(組み方によっちゃ他の命令も重くなりうるが、そう言うモノはスクリの組み方でどうにでもなる
描画をもし飛ばせたらゲームのスピードは10倍とか100倍とかにできちゃいます。
つまり、速度が欲しかったら描画を飛ばしたらいいんですよ。
描画してる時間がありそうなら描画、なさそうならぶっ飛ばす。
フレームスキップとは要するにそう言う処理です。
んでまぁ、こいつはその辺の時間管理を勝手にやってくれそうなモジュールです。
出来ることはサンプルがすべてです。
このモジュールはあなたのプログラムに組み込んで使用できます。
ですが、無断でのソースコードの転載・再配布はご遠慮ください。
/* mod_autoFPS.hsp */
// 自動 フレームスキップ モジュール v0.01 / 月影とも
#addition "mod_qpc.hsp"
#module mod_AutoFPS
#uselib "kernel32.dll"
#func Sleep "Sleep" int
#uselib "winmm.dll"
#ifdef timeGetTimeDouble
#define timeGetTime timeGetTimeDouble
#else
#cfunc timeGetTime "timeGetTime"
#endif
#define CurrentTime (1.0*timeGetTime@mod_AutoFPS())
#func timeBeginPeriod "timeBeginPeriod" int
#deffunc autoFps_SetFPS int fps
if StartTime == 0 : StartTime = CurrentTime
SampleCount = fps*3
FrameWait = 1000.0/fps
NextDrawTime = CurrentTime + FrameWait
dimtype LapTime, vartype("double"), 1
DrawnFrames = 0
LastDrawStart = CurrentTime
return
#deffunc autoFps_StartInternal
if CurrentTime < NextDrawTime : Sleep 1 : return 1
NextDrawTime += FrameWait : StartInternalTime = CurrentTime
return 0
#deffunc autoFps_StartDraw
CallCount++
if /* CallCount\\8=0 | */ NextDrawTime>CurrentTime {
LapTime(DrawnFrames\\SampleCount) = CurrentTime - LastDrawStart
LastDrawStart = CurrentTime
DrawnFrames++
return 0
}
return 1
#define global autoFps_CurrentFps _autoFps_CurrentFps()
#defcfunc _autoFps_CurrentFps
t = 0.0
repeat Length(LapTime)
t+=LapTime.cnt
loop
return 1000.0/t*length(LapTime)
#define global autoFps_mmtimer (CurrentTime@mod_autoFps-StartTime@mod_autoFps)
#global
/* そのサンプル */
#include "mod_autoFPS.hsp"
font MSGothic, 32
psx = 8
psy = 8
psg = 0
winx = ginfo_winx-32
winy = ginfo_winy-32
// FPSモジュール初期化
autoFps_SetFPS 60 // 引数: 理想FPS値
*mainloop
await 0
// ひたすらな内部処理。
// たとえば音ゲの音出しの精度は60fpsじゃ足りない。
InternalCounter1++
// フレーム毎 内部処理(描画以外の処理全部)
autoFps_StartInternal // 0が戻ったら内部処理開始。
if stat : goto *mainloop // まだ時ではない
InternalCounter2++
psy += psg
plx+=psx: ply+=psy
if plx<0 : plx=0 : psx=-psx
if ply<0 : ply=0 : psy=-psy
if plx>winx : plx=winx : psx=-psx
if ply>winy : ply=winy : psy=-psy
// 描画処理
autoFps_StartDraw // 0が戻ったら描画。
if stat : goto *mainloop // 時すでに遅し。次のチャンスを待て!
DrawnCounter++
redraw 0
color 0,0,0:boxf:color 255,255,255
pos 20,20:
mes "内部処理カウンタ1 : " + InternalCounter1
mes "内部処理カウンタ2 : " + InternalCounter2
mes "描画済みフレーム数 : " + DrawnCounter
mes "スキップ済フレーム : " + (InternalCounter2 - DrawnCounter)
mes "起動後経過時間 : " + strf("%.2f", autoFps_mmtimer/1000.0)
mes "FPS:"+ strf("%6.1f",autoFps_CurrentFps)
pos plx,ply : mes "●"
mes
redraw 1
// 描画に時間のかかるマシンのエミュレーション
//wait 5
goto *mainloop
おまけ。
/* mod_qpc.hsp */
// HSP3 で QueryPerformanceCounter しちゃうモジュール ver0.02
// まぁ、そこそこ精度のいいタイマーってことで使えないこともない。
#module mod_qpc
#uselib "kernel32.dll"
#func QueryPerformanceCounter "QueryPerformanceCounter" var
#func QueryPerformanceFreqency "QueryPerformanceFrequency" var
#defcfunc timeGetTimeDouble
if qp = 0 : qp = 0.0 : QueryPerformanceFreqency qp.0
QueryPerformanceCounter qp.1
return qp.1/qp.0*1000
#global
マシン語は要らないみたいです。
ヒントは 2^(-1022-52)にあるようで、いやはや^^;