10

Yampa-Framework で跳ねるボールをシミュレートしようとしています: 初期の x 位置、高さ、速度が与えられると、ボールは重力の規則に従って跳ね返るはずです。シグナル関数は入力として「Tip-Event」を受け取ります。これは、「ボールがチップされたときに速度が 2 倍になる」という考え方です。

ボールはうまく跳ねますが、転倒イベントが発生するたびに、関数は無限ループに入ります。おそらく遅延 (dSwitch、pre、notYet?) を追加する必要があると考えましたが、方法がわかりません。どんな助けでも大歓迎です!

{-# LANGUAGE Arrows #-} 

module Ball where

import FRP.Yampa

type Position  = Double
type Velocity  = Double
type Height    = Double

data Ball = Ball {
      height :: Height,
      width  :: Position,
      vel    :: Velocity
} deriving (Show)

type Tip = Event ()

fly :: Position -> (Height, Velocity) -> SF Tip (Ball, Event (Height,Velocity))
fly w0 (h0, v0) = proc tipEvent -> do
     let tip = (tipEvent == Event ())
     v <- (v0+) ^<< integral -< -10.0
     h <- (h0+) ^<< integral -< v 
     returnA -< (Ball h w0 v, 
                 if h < 0 then Event (0,(-v*0.6)) 
                  else if tip then Event (h, (v*2))
                   else NoEvent)

bounce w (h,v) = switch (fly w (h,v)) (bounce w)   

runBounce w (h,v)  = embed (bounce 10 (100.0, 10.0)) (deltaEncode 0.1 [NoEvent, NoEvent, NoEvent, Event (), NoEvent])

編集:ヒントが発生したときにフラグをフィードバックすることで無限ループを回避することができましたが、それでも正しい方法とは思えません...

fly :: Position -> (Height, Velocity, Bool) -> SF Tip (Ball, Event (Height,Velocity,Bool))
fly w0 (h0, v0, alreadyTipped) = proc tipEvent -> do
     let tip = tipEvent == Event () && (not alreadyTipped)
     v <- (v0+) ^<< integral -< -10.0
     h <- (h0+) ^<< integral -< v 
     returnA -< (Ball h w0 v, 
                 if h < 0 then Event (0,(-v*0.6), False) 
                  else if tip then Event (h, (v*2), True)
                   else NoEvent)

bounce w (h,v,alreadyTipped) = switch (fly w (h,v,alreadyTipped)) (bounce w)   
4

1 に答える 1

4

数日ハッキングした後、私は答えを見つけたと思います。トリックはnotYet、切り替えイベントを次の時点まで遅らせるために を使用することです。これによりfly、「古い」転倒イベントがなくなったときに切り替え (したがって への再帰呼び出し) が発生します。このsecond関数は、結果のタプルの 2 番目の部分のみが(Ball, Event (..))通過することを確認しnotYetます。これにより、無限ループが削除されますが、セマンティクスも変更されます。切り替えは 1 つの「タイム ステップ」後に行われるようになり、これにより速度が異なります。

この Yampa のことは、実際には非常に優れていますが、悲しいことに、見つけられるドキュメントはあまりありません。pre関数と関数が何に適しているのかまだわかりませんでしたiPreが、同様のコンテキストで使用できると思います。

fly :: Position -> (Height, Velocity) -> SF Tip (Ball, Event (Height,Velocity))
fly w0 (h0, v0) = proc tipEvent -> do
     let tip = tipEvent == Event ()
     v <- (v0+) ^<< integral -< -10.0
     h <- (h0+) ^<< integral -< v 
     returnA -< (Ball h w0 v, 
                 if h < 0 then Event (0,-v*0.6) 
                  else if tip then Event (h, v*2)
                   else NoEvent)

bounce w (h,v) = switch (fly w (h,v) >>> second notYet) (bounce w)   
于 2010-09-21T21:24:51.280 に答える