固定タイムステップシステム(60FPS)用に書かれたSonic physics engineのロジックを可変タイムステップ時代(正確にはSlick2D)にコピーしようとしています。可変タイムステップと重力/フリクション
オリジナルでは、ジャンプボタンを押したときに、プレーヤーのvelocity.y
は-6.5に設定され、それぞれの目盛り0.21875は重力をモデル化するためにvelocity.y
に追加されます。
論理更新が呼び出されるたびに、何ミリ秒経過したかを指定する時間デルタパラメータが渡されます。私が予想していたよりももっと多くのミリ秒が経過しているなら、ターゲットフレームの '残りの部分'を扱っている場合、更新ロジックを繰り返し、 '内側のデルタ'を1以下にします。
など。フレームが16msかかると予想される場合、はに16msかかります。ループは1回反復し、thisMiniTick
を1に渡します。デルタが16msではなく40msであれば、ループは3回実行され、そして最後に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;
}
詳細な回答をいただきありがとうございます。私が把握できなかった魔法の解決策がないことを確認することは安心です。なぜあなたは時間を差別化アプローチと誤解していますか?私はもともと自分の速度に経過時間を掛けていましたが、衝突コードが大きな書き換えを必要とすることを意味しました。プレイヤーは1つのティックでタイル全体より多くを移動してタイルをスキップすることができました。 –
ええ、私はそれを誇張しているかもしれませんが、私は、時間計算が、AI計算など、他のことをやりなおすためにどれくらいの時間がかかるかを人々がその値を使って調べようとしていることを見てきたと思います。あなたがそれを使うことができないということではなく、この問題に近づく様々な方法を使って、すべてを「delta」値にフックすると、最も信頼性の高い結果が得られます。 – jefflunt
衝突のために動きが速すぎるプレイヤーにとって、その問題にアプローチするにはいくつかの方法があります。 1人は、プレイヤーが横断したスペース全体で衝突計算を行うことになります(プレイヤーが3タイルを移動した場合、それらのいずれかで起こった衝突を把握して戻す必要があります)。 (ロジック更新間隔の最小/最大を調整する)ロジックの更新の粒度を増やすか、プレイヤーの移動を遅くするかのどちらかです。 – jefflunt