首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何实现与Netwire的碰撞(5.0.1)

如何实现与Netwire的碰撞(5.0.1)
EN

Stack Overflow用户
提问于 2016-08-04 06:16:57
回答 1查看 156关注 0票数 0

我试着用Netwire来模拟移动的物体,并且想知道实现像弹跳一样的东西的推荐方法。我遇到了几种可能的方法来做到这一点,我需要一些帮助,实际上让他们工作。

运动代码如下所示:

代码语言:javascript
复制
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)
  • 在网上使用Eventswitch。我不知道怎么用这个。
  • 通常使用箭头可用的(|||)函数。

前两个方案似乎是最好的选择,但我不知道如何实现它们。

我看到了其他类似的问题,但不同版本的网络之间的不兼容性使得答案对我没有用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-25 20:49:07

免责声明:我不能评论什么是“推荐”,但我可以展示一种方式,做你想做的。

我想描述两种方法:

第一种是使用有状态线,它与这是2013年的一个有点过时的教程非常相似,但基于Netwire 5.0.2。

第二种是使用无状态电线。因为它们是无状态的,所以需要反馈它们以前的值,这使得导线的输入类型和最终的连线组合变得更加复杂。否则他们就很相似了。

这两个示例中涉及的基本类型包括:

代码语言:javascript
复制
type Collision = Bool
type Velocity = Float
type Position = Float

有状态

您可以使用两条(有状态)连接来建模问题,然后将它们组合在一起。

一根线模拟速度,这是恒定的,并改变方向时,发生碰撞。它的(简化)类型是Wire s e m Collision Velocity,即它的输入是发生碰撞时,输出是当前的速度。

另一个模拟位置,并处理碰撞。它的(简化)类型是Wire s e m Velocity (Position, Collision),即它获取一个速度,计算新的位置并返回该位置,如果发生了碰撞。

最后将速度反馈到位置线,并将碰撞结果反馈到速度线中。

让我们看一下速度线的细节:

代码语言:javascript
复制
-- 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的水平,并在发生这种冲突时返回信息。

代码语言:javascript
复制
-- 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返回。

如果发生碰撞,下面的行检查边界并返回新位置,并返回与新状态的新线路。

最后,您可以使用recdelay将它们相互输入。完整的例子:

代码语言:javascript
复制
{-# 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)作为输入,我们只需提升一个函数来创建它:

代码语言:javascript
复制
-- 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变成

代码语言:javascript
复制
-- 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),并应用绑定检查。这样,不同的逻辑部分就可以很好地分开。

完整的例子:

代码语言:javascript
复制
{-# 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)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38759780

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档