10

我正在尝试使用 Yampa 框架模拟弹跳球:给定初始 x 位置、高度和速度,球应该根据重力规则弹跳。信号函数将“Tip-Event”作为输入,其想法是“当球被倾斜时,它的速度应该加倍”。

球弹得很好,但每次发生翻倒事件时,该函数都会进入无限循环。我想我可能需要添加一个延迟(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函数确保只有结果元组的第二部分(Ball, Event (..))将通过notYet。这消除了无限循环,但也改变了语义:切换现在发生在一个“时间步长”之后,这反过来又导致了不同的速度。

这个 Yampa 的东西实际上是相当不错的,遗憾的是没有太多的文档可以找到。我仍然找不到preandiPre函数有什么用,我认为它们可以在类似的环境中使用。

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 回答