为什么这个 Yampa 球弹跳会陷入无限循环?

发布于 2024-09-24 05:02:00 字数 1759 浏览 5 评论 0原文

我正在尝试使用 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)   

I'm trying to simulate a bouncing ball with the Yampa-Framework: Given an initial x-position, height and velocity, the ball should bounce according to gravity rules. The signal function takes a "Tip-Event" as input, the idea being "when the ball is tipped, it's speed should double".

The ball bounces nicely, but every time there is a tipping event, the function goes in to an endless loop. I figured I probably need to add a delay (dSwitch, pre, notYet?), but I do not know how. Any help would be appreciated!

{-# 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])

EDIT: I managed to avoid the endless loop by feeding back a flag when a tip occurred, but that still does not feel like the right way to do it...

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)   

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

送你一个梦 2024-10-01 05:02:00

经过几天的黑客攻击,我想我找到了答案。诀窍是使用 notYet 将切换事件延迟到下一个时间点,以便在“old”时发生切换(以及对 fly 的递归调用)。 “小费活动消失了。 second 函数确保只有结果元组 (Ball, Event (..)) 的第二部分将通过 notYet 进行处理。这消除了无限循环,但也改变了语义:现在切换发生在一个“时间步长”之后,这反过来又导致不同的速度。

这个 Yampa 的东西实际上相当不错,遗憾的是没有太多文档可找到。我仍然无法找出 preiPre 函数的用途,我认为它们可以在类似的上下文中使用。

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)   

After a few days hacking I think I found the answer. The trick is to use notYet to delay the switching event to the next point in time, so that the switching (and hence the recursive call to fly) occurs when the "old" tipping event is gone. The second function makes sure that only the second part of the result tuple (Ball, Event (..)) will be put through notYet. This removes the endless loop, but also changes the semantics: The switching now takes place one "time step" later, this in turn leads to a different speed.

This Yampa thing is actually quite nice, sadly there is not much documentation to find. I still could not find out what the pre and iPre functions are good for, I figure they can be used in a similar context.

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)   
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文