我正在努力了解FRP和Netwire.我最好的实用知识来源是这篇文章,但它有点过时,因为它是用Netwire 4编写的,我使用的是5.0版.我希望玩家控制正方形,从屏幕边缘反弹.
根据这篇文章,我有这个:
acceleration :: (Monad m, Monoid e) => Wire s e m (Set SDL.Keysym) Double
acceleration = pure (-80) . when (keyDown SDL.SDLK_LEFT)
<|> pure 80 . when (keyDown SDL.SDLK_RIGHT)
<|> pure 0
velocity :: (Monad m, HasTime t s, Monoid e) => Wire s e m (Double, Bool) Double
velocity = integralWith limit 0
where limit collision v = let newV = if collision then -v else v in clampMax maxV newV
challenge2 :: (MonadFix m, HasTime t s) => Wire s () m (Set SDL.Keysym) Double
challenge2 = proc keysDown -> do
a <- acceleration -< keysDown
rec v <- velocity -< (a, colls)
(pos, colls) <- position -< v
returnA -< pos
position :: (Monad m, HasTime t s, Monoid e) => Wire s e m Double (Double, Bool)
position = what to put here?
Run Code Online (Sandbox Code Playgroud)
我希望位置线能够整合速度,校正位置以保持在屏幕的范围内并产生指示发生碰撞的Bool.链接文章使用accumT,在当前版本的Netwire中,(AFAIK)消失了.并且它不是太漂亮 - 当有一根电线时手动集成......我知道,我可以使用integralWith来限制位置,但它不能产生比分数更多的东西.我试过这样的:
position = mkSF_ bounds . integral 0
where bounds pos = if trace (show pos) pos > 150 then (149, True) else if pos < 0 then (1, True) else (pos, False)
Run Code Online (Sandbox Code Playgroud)
请原谅我;).现在我知道整体线中有一个内部状态,我不会这样修改.
那么实现我想要的"正确方法"是什么?
我一直在关注同一篇文章,并尝试将其转换为 Netwire 5.0。这确实是一个有点棘手的问题。我最终创建了一个integralWith'与设计类似的新函数,integralWith但它接受单个值作为输入并产生两个值。
integralWith' ::
(Fractional a, HasTime t s)
=> (a -> (a, o)) -- Function for potentially limiting the integration
-- and producing a secondary output.
-> a -- Integration constant (aka start value).
-> Wire s e m a (a, o)
integralWith' correct = loop
where
loop x' =
mkPure $ \ds dx ->
let dt = realToFrac (dtime ds)
(x,b) = correct (x' + dt*dx)
in x' `seq` (Right (x', b), loop x)
Run Code Online (Sandbox Code Playgroud)
这几乎是直接从http://hackage.haskell.org/package/netwire-5.0.0/docs/src/FRP-Netwire-Move.html#integralWith复制的,我所做的只是摆弄类型以使其达到工作。
我的position函数最终看起来像这样。
position :: (Monad m, HasTime t s) => Wire s e m Double (Double, Bool)
position = integralWith' clamp 0
where
clamp p | p < 0 || p > 150 = (max 1 (min 149 p), True)
| otherwise = (p, False)
Run Code Online (Sandbox Code Playgroud)
由于我自己刚刚接触 FRP 和 Haskell,我不确定 netwire 库中是否已经存在这样的东西,或者它是否普遍有用,或者是否有一种我还没有见过的更简单的方法。