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)にあるようで、いやはや^^;