編輯:爲了回答這個問題,是的,你正確地使用你正在使用的近似值,它是歐拉的一階微分方程求解方法,並且對於你的目的來說足夠準確,特別是因爲用戶不會對角速度的絕對值來判斷你的反應。減少你的時間間隔將使其更加準確,但是這並不重要。
你可以用更少,更大的步驟做到這一點(見下文),但這種方式對我來說似乎最清晰,我希望它對你有用。
爲什麼要用這個更長的解決方案呢?即使eDisplay
發生在不規則的時間間隔,這也可以工作,因爲它會計算eDeltaT
。
讓我們給自己一個時間事件:
eTime :: Event t Int
eTime = bTime <@ eDisplay
要得到的DeltaT,我們需要跟蹤時間間隔傳球:
type TimeInterval = (Int,Int) -- (previous time, current time)
,所以我們可以將它們轉換成三角洲:
delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
我們應該如何更新一個新的時間間隔t2
?
tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
讓我們部分地應用該到的時候,給我們的時間間隔更新:
eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
,然後我們可以accumE
-accumulate上的初始時間間隔功能:
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
由於eTime是自渲染開始以來測量的,因此初始(0,0)
是適當的。
最後,我們可以有我們的DeltaT事件,只把它運用(fmap
平)delta
的時間間隔。
eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
現在我們需要更新角度,使用類似的想法。
我會做出一個角度更新,只需轉動的bAngularVelocity
成倍數:
bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity
那麼我們就可以用它來使eDeltaAngle
:(編輯:改到(+)
並轉換爲Double
)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)
和積累,以獲得角度:
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
如果你喜歡的俏皮話,你可以寫
eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
delta (t0,t1) = t1 - t0
tick t2 (t0,t1) = (t1,t2)
eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) =
,但我不認爲這是非常有啓發和說實話,我不知道我有我的固定性的權利,因爲我已經沒有在ghci中測試過。
當然,因爲我做了eAngle
而不是bAngle
,你需要
reactimate $ (draw gears) <$> eAngle
,而不是原來的
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
如果願意,可以通過使用戶chnge您BTIME的間隔,以同樣的方式作爲 aster example。 – AndrewC
@AndrewC,我猜[this](https://github.com/HeinrichApfelmus/reactive-banana/blob/master/reactive-banana -wx/src/Asteroids.hs)是你想要的鏈接嗎 – huon
是的0123.缺點:在低速時生澀,在高速下超載圖形引擎,醜陋我的建議回來了:使用角速度更多 – AndrewC