正如问题标题所说,我正在尝试创建一条产生位置的导线(在每一步中以一定的速度移动位置),“弹跳”掉其他物体。我能想到的最简单的例子是在一个盒子里移动,就像在一些屏幕保护程序中一样。
我写这个函数是为了做到这一点(仅适用于一个轴):
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
,但我不知道为什么。我想我可能会使用延迟错误或其他东西。
答案 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
我对箭头符号不是很熟悉所以我使用了Category
和Applicative
符号(使用.
的电线组合)。对于此任务,object_
特别方便。它在内部集成了速度和循环,我们需要做的就是给它一个修改函数并从输出中提取位置。
答案 1 :(得分:2)
啊,有机会回忆起我在BASIC和汇编程序中混合编写8位游戏时的知识!
可能发生的事情是,由于四舍五入错误,“球”被卡在墙的错误一侧。所以 - 如果你的墙是10.0,那么球在11.0001和10.0001之间振荡,v = -1.0,+ 1.0,-1.0等。不确定你如何打印位置来检查电线。
从(古代)记忆中,你要么想要计算弹跳,包括上一步中的任何“剩余”矢量,要么只是将球准确地放在墙上然后弹回它。