フレームレートに依存しない更新を実装するにはどうすればよいですか?


7

編集: jumpvelocityを変更して追加するものにし、yvelocityをjumpvelocity * tに等しくすることで問題を修正しました。これは私が今持っているものです:

if (GUI->Space && grounded){
    jumpvelocity = -185.f * 2  / gravity;
    grounded = false;

}

if(!grounded ){
    if(jumpvelocity < terminaly){
        jumpvelocity += 185.f * t * 4  / gravity;
        yvelocity = jumpvelocity * t;
    }
    else{
        jumpvelocity = terminaly;
        yvelocity = jumpvelocity * t / gravity;
    }
}
else{
    yvelocity = 0.f;
    jumpvelocity = 0.f;
}

助けてくれてありがとう。

私は重力を働かせようとしています。これまでのコードは

if (jumpvelocity < 0){
   yvelocity = jumpvelocity * t *2/gravity;
    jumpvelocity += 185.f*t * 2 / gravity;
}

else if(!grounded ){
    if(yvelocity < terminaly)
        yvelocity += t / gravity;
    else
        yvelocity = terminaly;
}

重力は上方にスケーリングし、高いほど落下とジャンプが遅くなります。デフォルト値は1です。ジャンプ速度は、プレイヤーがジャンプしたいときに185に設定されます。私の問題は、遅いフレームレートではゆっくりと落ちるが、フレームレートが高い場合と同じ速度でジャンプすることです。フレームに依存しないようにするにはどうすればよいですか?Tはデルタ時間です。


Velocityを使用して位置を変更するコードを表示できますか?
ヨルダンミロナス

だから、あなたのコメントをもう一度...問題は何ですか?xとyでまったく同じように機能します。
エンジニア、

私はSFMLを使用しているので、あなただけです。Move(xvelocty、yvelocity)。
user975989 '18 / 10/18

あなたの更新されたコードは、まだ絶対に持っているすべての私が指摘した問題を。jumpvelocity更新時に以前の値で平均化していないyvelocityため、低いフレームレートでは精度エラーが悪化します。速度に時間を掛けたyvelocityものなymovementので、実際に呼び出すのは当然のことです。jumpvelocityキャラクターが地面に触れなくなったときに更新を行っていますが、物理的な意味はありません。のチェックterminalyは更新前に行われるため、フレームレートが低くjumpvelocityなると、値が大きくなりterminaly、悪化します。
sam hocevar '19年

回答:


13

各メインループの繰り返し:

  1. システムタイマーを確認し、次のように保存しますcurrentTime(例:SDL_GetTicks())
  2. timeDelta = currentTime - lastTime
  3. timeDelta秒に変換(通常はmsまたはns単位)、次のように保存timeDeltaSeconds
  4. For each entity in entities: entity.position = velocityInUnitsPerSecond * timeDeltaSeconds
  5. lastTime = currentTime (ここの代わりにステップ1の前に行うこともできます)

...現在の数値を1秒あたりの単位になるように調整する必要があります。つまり、1FPSで意味をなすようにします。たとえば、キャラクターの水平速度が10分の1秒あたり2ピクセルであると予想した場合、20ピクセル/秒に設定する必要があります。そうすれば、上記は正しく動作します。

一部のアプリケーションでは、タイムステップを所定の量に修正することをお勧めします。この場合は、timestep != timeDelta。後者は実際に経過したシステム時間です。前者は、ゲームでロジックの更新を適用するたびにタイムアキュムレータから消費する量子化された量です。これは、有名な物理エンジンで見られるような反復ソルバーを使用している場合の統合を支援します。これは、計算を行うときにタイムステップが等しい必要があるためです。この場合、各ティックに残っいる時間を単純に使い尽くすだけでないため、残り時間の一部が残り、これらを累積して後のティックで使用する必要があります。これについて詳しくは、Glenn FiedlerによるFix Your Timestep読みください


ここで、回答に応答する方法がわからないので申し訳ありませんが、返された値に応じて、1/60秒以下のタイムステップがすでに設定されています。私のxvelocityはうまく機能し、フレームに依存しません(200.f * t)が、私のyvelocityはそうではありません。
user975989 '18 / 10/18

必要ではありませんvelocityInUnitsPerSecondが、経過時間中の平均速度です。速度が一定であれば、コードは正しいです。重力の場合のように速度が線形に変化する場合、その値は0.5 * (OldVelocity + NewVelocity)です。それ以外の場合は、精度の問題を回避するために、より小さなタイムステップで統合する必要がある場合があります。
sam hocevar '18年

0

jumpvelocity全然必要ないようです。ジャンプとは、速度を特定の値に即座に設定することを意味します。足が地面に触れなくなると、速度を変更できる唯一のことは重力(および空気抵抗、ターミナル速度を使用して実装する)です。

また、浮動小数点の除算は非常に遅いです。の1.0f / gravity代わりに保存することをお勧めしますgravity

最後に、1つのフレームでyvelocityがを超える可能性がありterminalyます。

私のおすすめ:

if (GUI->Space && grounded) {
    yvelocity = 185.f;
    grounded = false;
} else if (!grounded ) {
    yvelocity += t * inv_gravity;
    if (yvelocity > terminaly)
        yvelocity = terminaly;
}

また、以下は正確ではないことに注意してください。

ypos += t * yvelocity;

あなたがする必要があります:

ypos += t * 0.5f * (old_yvelocity + yvelocity);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.