シミュレーションゲームを作成中なのですが、ちょっと悩んでいます。
1. 座標を計算するためにタイマーを使って1/30秒ごとに演算を行う。
2. 計算結果の数値を使って画面を描画する。
1は問題なくできるのですが、2をどう実現させようかと思いまして・・・。
「最高30fpsとして、できるだけ高フレームレートで表示できるように努力する」
方法を探しています。
まず「Application.OnIdleを使って暇なときに描画」を考えつきました。
しかし、キーリピートが発生すると負荷が高くなるせいか、一時的ですが描画が
完全停止してしまい、ちょっとゲームに使うには・・・でした。
次に、サブスレッドを生成し、メインで数値計算、サブで描画をさせる方法を考えました。
サブスレッドは、下記のように暇さえあればひたすら描画を行うようにしてみました。
while not terminated do begin
start := timegettime;
if メインで計算された座標が更新されていたら then Synchronize(座標);
stop := timegettime;
writetime := stop - start;
if (writetime < 33) then sleep(33 - writetime);
// 描画が33msより早かったら、30fpsを超えないように休憩
sleep(0);
// もしスライスされた時間が余ってたらメインスレッドに譲ります
end;
そして、Synchronize内でメインFormに対してDirectDrawで描画命令を出しています。
しかし、この方法で最初はうまくいくのですが、描画が忙しくなってくると
Drawが数秒おきに一瞬停止し、カクカク動くようになってしまいました。
複数のPCで試したのですが、スペックに関係なく描画がスムーズだったり、
カクカクで使い物にならなかったりして、原因が掴めないでいます。
いちばん時間がかかる描画処理をSynchronize経由メインスレッドでやっているので、
サブスレッド化する意味自体無いのでしょうか・・・。参考までに、sleep(0)を外すと
メインスレッドのタイマーも遅延でガタガタになってしまいました。
もし、他に素敵なアイデアがありましたら是非お教えください。
DirectXを使えば、垂直帰線期間中に描画する機能があります。
# OpenGLにもあるはずですが、未確認
ゲームなど、描画速度が命のプログラムでは、ダブルバッファリングして、垂直帰線中に画面を入れ替えるというのが定石です。
OpenGLは、いかがですか?
GLUTを使わなければuses節にOpenGLを追加するだけで、意外と簡単に実現できると思います。
(ゲームの内容にもよりますが、、、。)
ありがとうございます。
描画にはDelphiXを使っていて、vsyncのことは考えたこともありませんでした。
描画速度を保証する方法、ありそうですね。それ系の本でちょっと勉強してみます。
(OpenGLは触ったことすらないので・・・(汗)
ツイート | ![]() |