Netwire - 如何构建能够产生位置,弹跳墙壁的电线?

时间:2013-08-22 12:12:49

标签: haskell netwire

使用netwire-4.0.7

正如问题标题所说,我正在尝试创建一条产生位置的导线(在每一步中以一定的速度移动位置),“弹跳”掉其他物体。我能想到的最简单的例子是在一个盒子里移动,就像在一些屏幕保护程序中一样。

我写这个函数是为了做到这一点(仅适用于一个轴):

import Control.Wire
bouncyWire :: Double -> Double -> Double -> Double -> Wire () IO a Double
bouncyWire startPosition startVelocity lowerBound upperBound = proc _ -> do
  rec
     v <- delay startVelocity -< if p < lowerBound || p > upperBound
                                    then -v else v
     p <- integral_ startPosition -< v
  returnA -< p

(我实际上将它与不同的monad一起使用,但是这段代码实际上并没有使用它,这会使问题过于复杂。)

然后用counterSession $ 1/60踩它,我遇到了问题 - 而不是从墙上“弹跳”,它会卡在那里。我认为发生的事情是它一直在翻转速度v,但我不知道为什么。我想我可能会使用延迟错误或其他东西。

2 个答案:

答案 0 :(得分:5)

正如Richard Huxton解释的那样,你的电线卡在边境后面。一种解决方案是检查您是否只是反转速度,始终将它们指向正确的方向。这样,电线总是从边框后面。另一个解决方案是,如果它出来,将位置改回边框内部。这样,线路永远不会被认为落后(这是你通常想要在游戏中做的事情)。结合起来可能看起来像

import Prelude hiding ((.), id)
import Control.Category
import Control.Wire
import Control.Wire.Wire
import Control.Wire.Prefab.Move

bouncyWire :: (Monad m)
           => Double -> Double -> Double -> Double -> Wire () m a Double
bouncyWire startPosition startVelocity lowerBound upperBound =
    objPosition <$> object_ update (ObjectState startPosition startVelocity)
        . constant (Accelerate 0, ())
  where
    update _ s@(ObjectState pos vel)
        | (pos > upperBound)    = ObjectState (2*upperBound - pos) (- abs vel)
        | (pos < lowerBound)    = ObjectState (2*lowerBound - pos) (abs vel)
        | otherwise             = s

我对箭头符号不是很熟悉所以我使用了CategoryApplicative符号(使用.的电线组合)。对于此任务,object_特别方便。它在内部集成了速度和循环,我们需要做的就是给它一个修改函数并从输出中提取位置。

答案 1 :(得分:2)

啊,有机会回忆起我在BASIC和汇编程序中混合编写8位游戏时的知识!

可能发生的事情是,由于四舍五入错误,“球”被卡在墙的错误一侧。所以 - 如果你的墙是10.0,那么球在11.0001和10.0001之间振荡,v = -1.0,+ 1.0,-1.0等。不确定你如何打印位置来检查电线。

从(古代)记忆中,你要么想要计算弹跳,包括上一步中的任何“剩余”矢量,要么只是将球准确地放在墙上然后弹回它。