Почему этот подпрыгивающий мяч Yampa входит в бесконечный цикл? - PullRequest
10 голосов
/ 19 сентября 2010

Я пытаюсь смоделировать прыгающий шар с помощью Yampa-Framework: учитывая начальное положение x, высоту и скорость, шар должен отскочить в соответствии с правилами гравитации.Функция сигнала принимает в качестве входных данных «событие-наконечник», идея заключается в том, что «когда мяч опрокинут, его скорость должна удвоиться».

Мяч отскакивает приятно, но каждый раз, когда происходит событие опрокидывания,функция входит в бесконечный цикл.Я подумал, что мне, вероятно, нужно добавить задержку (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)   

1 Ответ

4 голосов
/ 22 сентября 2010

После нескольких дней взлома я думаю, что нашел ответ.Хитрость заключается в том, чтобы использовать notYet для отсрочки события переключения на следующий момент времени, чтобы переключение (и, следовательно, рекурсивный вызов fly) происходило, когда «старое» событие опрокидывания прошло.Функция second гарантирует, что только вторая часть кортежа результата (Ball, Event (..)) будет пропущена через notYet.Это удаляет бесконечный цикл, но также меняет семантику: переключение теперь происходит на один «временной шаг» позже, что, в свою очередь, приводит к другой скорости.не много документации, чтобы найти.Я до сих пор не смог выяснить, для чего нужны функции 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)   
...