0

固定タイムステップシステム(60 FPS)用に作成されたSonic物理エンジンのロジックを可変タイムステップ年齢(正確にはSlick2D)でコピーしようとしています。

オリジナルでは、ジャンプボタンを押すと、プレーヤーのvelocity.y値が-6.5に設定され、各ティック0.21875がvelocity.yモデルの重力に追加されます。

ロジックアップデートが呼び出されるたびに、何ミリが経過したかを指定するタイムデルタパラメータが渡されます。予想よりも多くのミリ秒が経過した場合は、更新ロジックを繰り返し、ターゲットフレームの「余り」を処理している場合は最大1以下の「内部デルタ」を渡します。

たとえば、フレームに16ミリ秒かかると予想され、 16ミリ秒かかる場合、ループ1回繰り返され、1として渡さthisMiniTickれます。デルタが16ミリ秒ではなく40ミリ秒の場合、ループは3回実行され、1、1、最後に渡されます。 0.5。

これらの内部更新ループのそれぞれで実行できると誤って考えましたvelocity.y += (gravity * thisMiniTickRelative)が、これは機能しません。より速いフレームレートでは十分な重力が適用されず、より高いジャンプが発生し、より遅いフレームレートではジャンプが低くなります(ただし、それほど目立つ場所ではありません)。

事実上すべてのフレームレートで機能するこれを行う方法はありますか、それとも上限と下限を設定する必要がありdeltaますか?

'内部更新'ループ:

    float timeRemaining = delta/1000f; 
    while(timeRemaining > 0)
    {
        float thisMiniTick = Math.min(timeRemaining, 1f / FRAMES_PER_SECOND);
        float thisMiniTickRelative = thisMiniTick / (1f / FRAMES_PER_SECOND);

        updateInput(container, game, thisMiniTickRelative);
        if (playerAirState)
        {
            playerVelocity.y += (GRAVITY * thisMiniTickRelative);
        }
        clampPlayerVelocity();
        playerPosition.add(playerVelocity);
        doCollisions();
        timeRemaining -= thisMiniTick;
    }
4

1 に答える 1

2

「上界と下界の設定に頼る」とは考えないでくださいdelta。アプリケーションとスレッドは、システムに対する他のすべての要求の中でも、アプリのOSスケジューリング時間の影響を受けます。また、注意する必要があることもあります。この課題は、PCゲームでは、シングルタスクオペレーティングシステムからマルチタスクオペレーティングシステムに移行した日と同じくらい古くからあります。

Slickを使用すると、ロジックの更新をレンダリングの更新から切断できます(また、切断する必要があります)。これが、delta値がアプリケーションに渡される理由です。これを行うには、.setMinimumLogicUpdateIntervalメソッドと.setMaximumUpdateIntervalメソッドを使用します。

Slickのプロジェクトを含め、私が取り組んできたプロジェクトでは、1秒あたり30〜60のロジック更新(更新間の30.3ミリ秒から16.6ミリ秒)のすべてがうまく機能し、動きに必要なスムーズさを提供します。物理学、および衝突計算。

文字通り、それが意味するのは、1秒あたり30〜60のロジック更新の場合、次のことを行う必要があるということです。

container.setMinimumLogicUpdateInterval(16);  // max 60 logic updates per second
container.setMaximumLogicUpdateInterval(31);  // min 30 logic updates per second

また、値を計算しようとするのはよくある間違いtimeRemaingですが、これは実行したくありません。あなたは単にあなたがどれだけ動いたか、どれだけの時間が経過したかを掛けたいのです。30ミリ秒が経過した場合、それは約1/33秒なので、ゲームオブジェクトを1秒で移動する量の1/33だけ移動する必要があります。

float timeElapsed = delta/1000f;

playerVelocity.y += (GRAVITY * timeElapsed);

上で指定したように上限/下限を設定するtimeElapsedと、常にとの間の値に0.03なり0.06ます。ゲームが停滞し、フレームレートが低下した場合でも、ロジックの更新はこれらの範囲を超えません。代わりに、ゲーム全体が遅くなるように見えますが(画面に表示が多すぎた昔のセガの時代と同じように)、衝突と物理計算は期待どおりに機能します。

于 2011-12-19T02:45:35.233 に答える