我試圖複製Sonic physics engine的邏輯,這是寫在一個固定時間步進系統(60 FPS),在一個可變的時間步長(Slick2D,準確地說)。可變步時間和重力/摩擦
在原來按下跳轉按鈕時,玩家的velocity.y
設置爲-6.5,並且每個勾號0.21875被添加到velocity.y
以模擬重力。
每次我調用邏輯更新時,都會傳遞一個時間增量參數,指定已經通過了多少毫秒。如果更多millis已經超過了我的預期,那麼我重複更新邏輯,傳遞一個「內三角洲」,如果我們正在處理目標幀的「剩餘部分」,最多爲1或更小。
E.g.如果我們期望一個幀需要16ms,並且確實是需要16ms,則該循環將迭代一次並且將thisMiniTick
作爲1傳遞。如果該增量不是16ms但是40ms,則該循環將執行三次,最後是0.5。
我錯誤地認爲,在每個內部更新循環中,我可以做velocity.y += (gravity * thisMiniTickRelative)
,但這不起作用。在較快的幀速率下,不會引起足夠的重力,導致較高的跳躍,而在較慢的幀率下,跳躍較低(儘管沒有明顯的地方)。
有沒有辦法做到這一點,幾乎適用於所有framerate,或者我必須求助於設置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;
}
感謝您的詳細解答,我很欣慰地看到沒有一些我無法想象的神奇解決方案。你爲什麼會認爲timeRemaining方法是一個錯誤?我原本的速度已經乘以時間流逝,但這意味着碰撞代碼需要大量重寫,因爲玩家可以在一個嘀嗒聲中行進超過一整塊的瓦片,從而「跳過」瓦片。 – 2011-12-19 08:07:43
是的,我可能誇大了它,但我猜我在哪裏看到'timeremaining'出現錯誤的時候,人們試圖使用這個值來計算他們還有多少時間做其他事情,比如人工智能計算等等。這並不是說你不能使用它,只是通過各種方法來解決這個問題,把所有東西都加入到delta值中會給你提供最可靠的結果。 – jefflunt 2011-12-19 14:12:37
對於因碰撞而移動速度過快的玩家,有幾種方法可以解決這個問題。一個是在玩家穿過的整個空間進行碰撞計算(如果玩家移動了3個方塊,那麼你需要計算出任何碰撞發生的碰撞並將其反彈回來;另一個更簡單方法是增加邏輯更新的粒度(調整最小/最大邏輯更新間隔),或者讓播放器移動得更慢 – jefflunt 2011-12-19 14:14:38