3

使用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,但我不知道为什么。我想我可能使用延迟错误或其他东西。

4

2 回答 2

5

正如理查德赫克斯顿解释的那样,你的电线卡在边界后面。一种解决方案是检查您不只是反转速度,而是始终将它们指向正确的方向。这样,电线总是从边界后面。另一种解决方案是,如果它离开,则将位置更改回边界内。这样,电线永远不会被认为落后(这是您通常想要在游戏中做的事情)。结合在一起它可能看起来像

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_特别得心应手。它在内部集成了速度和循环,我们需要做的就是给它一个修改函数并从输出中提取位置。

于 2013-08-22T16:27:15.230 回答
2

啊,一个机会来回收我那些用 BASIC 和汇编程序混合编写 8 位游戏的日子里的知识!

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

从(古老的)记忆中,您要么想要计算反弹,包括上一步中的任何“剩余”矢量,要么只是在反弹之前将球准确地放在墙上。

于 2013-08-22T15:03:14.197 回答