編集:質問に答えるには、はい、使用している近似を使用するのは正しいです。これは、一次微分方程式を解くオイラーの方法であり、特にユーザーがあなたを判断するために横たわっている角速度の絶対値。時間間隔を短くすると、より正確になりますが、それは重要ではありません。
これは、より少ない、より大きなステップで行うことができます (以下を参照)。しかし、この方法が最も明確に思えます。
なぜこの長い解決策を気にするのですか? これは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
、初期時間間隔でその関数を累積できます。
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
eTime はレンダリングの開始から測定されるため、イニシャル(0,0)
が適切です。
最後に、時間間隔に( fmap
ping)を適用するだけで、DeltaT イベントを発生させることができます。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)