6

セットアップ:

OpenGL と一緒に Reactive Banana を使用しており、回転させたいギアがあります。次の信号があります。

bTime :: Behavior t Int -- the time in ms from start of rendering
bAngularVelosity :: Behavior t Double -- the angular velocity
                                      -- which can be increase or
                                      -- decreased by the user
eDisplay :: Event t ()     -- need to redraw the screen
eKey :: Event t KeyState   -- user input

最終的に、bAngleどちらが描画関数に渡されるかを計算する必要があります。

reactimate $ (draw gears) <$> (bAngle <@ eDisp)

角度は簡単に計算できます。a = ∫v(t) dt

質問:

私がやりたいことは、各 eDisplay イベント (または、必要に応じてより頻繁に) について、この積分を概算することだと思います。a = ∑ v Δtこれは正しい方法ですか?もしそうなら、どのように私はΔtから取得できbTimeますか?

関連項目: answer が関数を使用していると思われmapAccumます。もしそうなら、私の他の質問も見てください。

4

2 に答える 2

6

編集:質問に答えるには、はい、使用している近似を使用するのは正しいです。これは、一次微分方程式を解くオイラーの方法であり、特にユーザーがあなたを判断するために横たわっている角速度の絶対値。時間間隔を短くすると、より正確になりますが、それは重要ではありません。

これは、より少ない、より大きなステップで行うことができます (以下を参照)。しかし、この方法が最も明確に思えます。

なぜこの長い解決策を気にするのですか? これは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)が適切です。

最後に、時間間隔に( fmapping)を適用するだけで、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)
于 2012-09-08T15:05:52.423 に答える