質問
趣味としてLinuxでOpenGLとSDLを使用してC ++で3Dゲームをゼロから構築し、プログラミングのこの分野について詳しく学びます。
ゲームの実行中に時間をシミュレートする最良の方法について疑問に思います。明らかに次のようなループがあります。
void main_loop()
{
while(!quit)
{
handle_events();
DrawScene();
...
SDL_Delay(time_left());
}
}
SDL_Delayとtime_left()を使用して、約33 fpsのフレームレートを維持しています。
次のようないくつかのグローバル変数が必要だと思っていました
int current_hour = 0;
int current_min = 0;
int num_days = 0;
Uint32 prev_ticks = 0;
次に、次のような関数:
void handle_time()
{
Uint32 current_ticks;
Uint32 dticks;
current_ticks = SDL_GetTicks();
dticks = current_ticks - prev_ticks; // get difference since last time
// if difference is greater than 30000 (half minute) increment game mins
if(dticks >= 30000) {
prev_ticks = current_ticks;
current_mins++;
if(current_mins >= 60) {
current_mins = 0;
current_hour++;
}
if(current_hour > 23) {
current_hour = 0;
num_days++;
}
}
}
その後、メインループでhandle_time()関数を呼び出します。
コンパイルして実行します(printfを使用して現時点でコンソールに時間を書き込みます)が、これが最善の方法かどうか疑問に思っています。もっと簡単な方法やもっと効率的な方法はありますか?
解決
これは他のゲーム関連のスレッドで以前に言及しました。いつものように、グレンフィードラーの Game Physicsシリーズ の提案に従ってください。 p>
やりたいことは、時間差を累積することで得られる一定のタイムステップを使用することです。 1秒間に33個の更新が必要な場合、一定のタイムステップは1/33になります。これを更新頻度と呼ぶこともできます。また、ゲームロジックは一緒になっていないため、レンダリングからゲームロジックを分離する必要があります。マシンが許す限り高速にレンダリングしながら、低い更新頻度を使用できるようにしたい。サンプルコードを次に示します。
running = true;
unsigned int t_accum=0,lt=0,ct=0;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type){
...
}
}
ct = SDL_GetTicks();
t_accum += ct - lt;
lt = ct;
while(t_accum >= timestep){
t += timestep; /* this is our actual time, in milliseconds. */
t_accum -= timestep;
for(std::vector<Entity>::iterator en = entities.begin(); en != entities.end(); ++en){
integrate(en, (float)t * 0.001f, timestep);
}
}
/* This should really be in a separate thread, synchronized with a mutex */
std::vector<Entity> tmpEntities(entities.size());
for(int i=0; i<entities.size(); ++i){
float alpha = (float)t_accum / (float)timestep;
tmpEntities[i] = interpolateState(entities[i].lastState, alpha, entities[i].currentState, 1.0f - alpha);
}
Render(tmpEntities);
}
これはアンダーサンプリングとオーバーサンプリングを処理します。ここで行ったように整数演算を使用する場合、マシンの速度がどれだけ遅くても速くても、ゲームの物理特性は100%に近い確定性を持つ必要があります。これは、一定の時間間隔で時間を増やす利点です。レンダリングに使用される状態は、以前の状態と現在の状態の間を補間することによって計算されます。時間アキュムレータ内の残りの値が補間係数として使用されます。これにより、タイムステップの大きさに関係なく、レンダリングがスムーズになります。
他のヒント
既に指摘されている問題(時間の構造体を使用してhandle_time()に渡すと、30分ごとに分が増加します)以外は、ゲームでの実行時間を追跡するためのソリューションは問題ありません。
ただし、頻繁に発生する必要のあるほとんどのゲームイベントでは、実際の時間ではなくメインゲームループに基づいて、異なるfpsで同じ割合で発生するようにする必要があります。
本当に読みたいグレンの投稿の1つは、タイムステップを修正することです!。このリンクを確認した後、マッドが彼の回答。
私はLinux開発者ではありませんが、ティックをポーリングするのではなく、タイマーを使用したい場合があります。
http://linux.die.net/man/2/timer_create
編集:
SDLはタイマーをサポートしているようです: SDL_SetTimer