I'm trying to understand FRP and Netwire. My best source of practical knowledge is this post, however it's a bit outdated, as it's written in Netwire 4, and I'm using version 5.0. I want to have player controlled square, that bounces off screen edges.
Based on that post I have this:
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?
I want position wire to integrate velocity, correct the position to stay within bounds of the screen and produce Bool indicating that collision occurred. Linked article uses accumT, which, in current version of Netwire, is (AFAIK) gone. And it's not too pretty - integrating by hand when there is a wire for that... I know, that I can limit position using integralWith, but it can't produce anything more than a Fractional. I tried like this:
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)
And forgive me that ;). Now I know that there is an internal state in integral wire, which I do not modify this way.
So what is the 'correct way' to achieve what I want?
I was following the same article along, trying to translate it to Netwire 5.0 as well. This was indeed a bit of a sticky point. I ended up creating a new
integralWith'
function similar in design to theintegralWith
but which takes as input a single value and produces two values.This is almost directly copied from http://hackage.haskell.org/package/netwire-5.0.0/docs/src/FRP-Netwire-Move.html#integralWith, all I did was fiddle with the types to get it to work.
My
position
function ended up looking like this.As I am just getting into FRP and Haskell myself, I'm not sure if something like this already exists in the netwire library or not, or if it is even generally useful, or if there is a simpler way that I have not yet seen.