我试着用Netwire来模拟移动的物体,并且想知道实现像弹跳一样的东西的推荐方法。我遇到了几种可能的方法来做到这一点,我需要一些帮助,实际上让他们工作。
运动代码如下所示:
type Pos = Float
type Vel = Float
data Collision = Collision | NoCollision
deriving (Show)
motion :: (HasTime t s, MonadFix m) => Pos -> Vel -> Wire s Collision m a Pos
motion x0 v0 = proc _ -> do
rec
v <- vel <<< delay 0 -< x
x <- pos x0 -< v
returnA -< x
pos :: (HasTime t s, MonadFix m) => Pos -> Wire s Collision m Vel Pos
pos x0 = integral x0
main :: IO ()
main = testWire clockSession_ (motion 0 5)什么是建议的方式,使一个速度箭头,导致反弹在一定的位置,如x=20?
我看到了三种不同的方法可以做到这一点:
-->函数,这似乎是最简单的。我有一个使用这个函数的原型,但是我不知道如何根据碰撞时的速度来制作一个新的速度箭头,我只能使用一个固定的值,如果物体能够加速的话,它是没有用的。
vel ::(HasTime t s,MonadFix m) =>钢丝的碰撞m Pos Vel vel =纯5。除非(>20) ->纯(-5)Event和switch。我不知道怎么用这个。(|||)函数。前两个方案似乎是最好的选择,但我不知道如何实现它们。
我看到了其他类似的问题,但不同版本的网络之间的不兼容性使得答案对我没有用。
发布于 2016-11-25 20:49:07
免责声明:我不能评论什么是“推荐”,但我可以展示一种方式,做你想做的。
我想描述两种方法:
第一种是使用有状态线,它与这是2013年的一个有点过时的教程非常相似,但基于Netwire 5.0.2。
第二种是使用无状态电线。因为它们是无状态的,所以需要反馈它们以前的值,这使得导线的输入类型和最终的连线组合变得更加复杂。否则他们就很相似了。
这两个示例中涉及的基本类型包括:
type Collision = Bool
type Velocity = Float
type Position = Float有状态
您可以使用两条(有状态)连接来建模问题,然后将它们组合在一起。
一根线模拟速度,这是恒定的,并改变方向时,发生碰撞。它的(简化)类型是Wire s e m Collision Velocity,即它的输入是发生碰撞时,输出是当前的速度。
另一个模拟位置,并处理碰撞。它的(简化)类型是Wire s e m Velocity (Position, Collision),即它获取一个速度,计算新的位置并返回该位置,如果发生了碰撞。
最后将速度反馈到位置线,并将碰撞结果反馈到速度线中。
让我们看一下速度线的细节:
-- stateful fixed velocity wire that switches direction when collision occurs
velocity :: Velocity -> Wire s e m Collision Velocity
velocity vel = mkPureN $ \collision ->
let nextVel = if collision then negate vel else vel
in (Right nextVel, velocity nextVel)mkPureN创建一个只依赖于输入和它自己的状态(而不是Monad或时间)的有状态连线。状态是当前速度,如果Collision=True作为输入传递,下一个速度将被否定。返回值是速度值和具有新状态的新导线的一对。
对于这个位置,直接使用integral导线是不够的。我们需要一个增强的、“有界”的integral版本,该版本确保值保持在低于上限且大于0的水平,并在发生这种冲突时返回信息。
-- bounded integral [0, bound]
pos :: HasTime t s => Position -> Position -> Wire s e m Velocity (Position, Collision)
pos bound x = mkPure $ \ds dx ->
let dt = realToFrac (dtime ds)
nextx' = x + dt*dx -- candidate
(nextx, coll)
| nextx' <= 0 && dx < 0 = (-nextx', True)
| nextx' >= bound && dx > 0 = (bound - (nextx' - bound), True)
| otherwise = (nextx', False)
in (Right (nextx, coll), pos bound nextx)mkPure类似于mkPureN,但允许连接依赖于时间。
dt是时差。
nextx'是新的职位,因为它将由integral返回。
如果发生碰撞,下面的行检查边界并返回新位置,并返回与新状态的新线路。
最后,您可以使用rec和delay将它们相互输入。完整的例子:
{-# LANGUAGE Arrows #-}
module Main where
import Control.Monad.Fix
import Control.Wire
import FRP.Netwire
type Collision = Bool
type Velocity = Float
type Position = Float
-- bounded integral [0, bound]
pos :: HasTime t s => Position -> Position -> Wire s e m Velocity (Position, Collision)
pos bound x = mkPure $ \ds dx ->
let dt = realToFrac (dtime ds)
nextx' = x + dt*dx -- candidate
(nextx, coll)
| nextx' <= 0 && dx < 0 = (-nextx', True)
| nextx' >= bound && dx > 0 = (bound - (nextx' - bound), True)
| otherwise = (nextx', False)
in (Right (nextx, coll), pos bound nextx)
-- stateful fixed velocity wire that switches direction when collision occurs
velocity :: Velocity -> Wire s e m Collision Velocity
velocity vel = mkPureN $ \collision ->
let nextVel = if collision then negate vel else vel
in (Right nextVel, velocity nextVel)
run :: (HasTime t s, MonadFix m) => Position -> Velocity -> Position -> Wire s () m a Position
run start vel bound = proc _ -> do
rec
v <- velocity vel <<< delay False -< collision
(p, collision) <- pos bound start -< v
returnA -< p
main :: IO ()
main = testWire clockSession_ (run 0 5 20)无国籍
无状态变量与有状态变量非常相似,只不过状态漫游到连接的输入类型,而不是创建连接的函数的参数。
因此,速度线以一个元组(Velocity, Collision)作为输入,我们只需提升一个函数来创建它:
-- pure stateless independent from time
-- output velocity is input velocity potentially negated depending on collision
velocity :: Monad m => Wire s e m (Velocity, Collision) Velocity
velocity = arr $ \(vel, collision) -> if collision then -vel else vel您还可以使用来自Control.Wire.Core的函数Control.Wire.Core(然后取消对Monad m的限制)。
pos变成
-- pure stateless but depending on time
-- output position is input position moved by input velocity (depending on timestep)
pos :: HasTime t s => Position -> Wire s e m (Position, Velocity) (Position, Collision)
pos bound = mkPure $ \ds (x,dx) ->
let dt = realToFrac (dtime ds)
nextx' = x + dt*dx -- candidate
(nextx, coll)
| nextx' <= 0 && dx < 0 = (-nextx', True)
| nextx' >= bound && dx > 0 = (bound - (nextx' - bound), True)
| otherwise = (nextx', False)
in (Right (nextx, coll), pos bound)在这里,我们仍然需要使用mkPure,因为没有任何函数可以专门用于依赖时间的无状态电线。
要连接这两条线,我们现在必须将速度输出输入到自己和位置,从pos线将位置输入到自己,并将碰撞信息输入速度线。
但是实际上,使用无状态线,您还可以分离pos线路的“集成”和“边界检查”部分。然后,pos导线是一个直接返回上面nextx'的Wire s e m (Position, Velocity) Position,而boundedPos导线是一个从pos获取新位置和速度的Wire s e m (Position, Velocity) (Position, Collision),并应用绑定检查。这样,不同的逻辑部分就可以很好地分开。
完整的例子:
{-# LANGUAGE Arrows #-}
module Main where
import Control.Monad.Fix
import Control.Wire
import FRP.Netwire
type Collision = Bool
type Velocity = Float
type Position = Float
-- pure stateless but depending on time
-- output position is input position moved by input velocity (depending on timestep)
pos :: HasTime t s => Wire s e m (Position, Velocity) Position
pos = mkPure $ \ds (x,dx) ->
let dt = realToFrac (dtime ds)
in (Right (x + dt*dx), pos)
-- pure stateless independent from time
-- input position is bounced off the bounds
boundedPos :: Monad m => Position -> Wire s e m (Position, Velocity) (Position, Collision)
boundedPos bound = arr $ \(x, dx) ->
let (nextx, collision)
| x <= 0 && dx < 0 = (-x, True)
| x >= bound && dx > 0 = (bound - (x - bound), True)
| otherwise = (x, False)
in (nextx, collision)
-- pure stateless independent from time
-- output velocity is input velocity potentially negated depending on collision
velocity :: Monad m => Wire s e m (Velocity, Collision) Velocity
velocity = arr $ \(vel, collision) -> if collision then -vel else vel
-- plug the wires into each other
run :: (HasTime t s, MonadFix m) => Position -> Velocity -> Position -> Wire s () m a Position
run start vel bound = proc _ -> do
rec
v <- velocity <<< delay (vel, False) -< (v, collision)
lastPos <- delay start -< p'
p <- pos -< (lastPos, v)
(p', collision) <- boundedPos bound -< (p, v)
returnA -< p'
main :: IO ()
main = testWire clockSession_ (run 0 5 20)https://stackoverflow.com/questions/38759780
复制相似问题