Your answer is one click away!

cies February 2016
### How to create an Event that contains the difference between the value at current tick and the value at the value at previous tick?

I'm using `reactive-banana`

and `sdl2`

(using this glue library) for a game-like project. A `Behavior`

is created for the "absolute mouse location", as well as a `Behavior`

for the "relative mouse location" (a.k.a. the mouse movement). When not using FRP this works well, but with FRP the "relative mouse location" becomes a problem: it seems only a small amount of the data comes through. I suspect this happens because the underlying "SDL events" (that we represent with a `Behavior`

) do not line up nicely with the tick `Event`

s.

So I want to calculate my own mouse movement, by simply comparing the mouse location at the current tick with the location at the previous tick. I'm not sure if this will solve my problems, but I have good hope :)

First of all I'm lost on how to approach it: the `State`

monad, or an `IORef`

, or does `reactive-banana`

provide another means?

I'll give a small excerpt of the code I currently have:

```
makeNetwork :: GraphicsData -> SDLEventSource -> MomentIO ()
makeNetwork gd sdlEventSource = mdo
tickE <- tickEvent sdlEventSource
mouseMovementB <- fromPoll SDL.getRelativeMouseLocation
mousePositionB <- fromPoll SDL.getAbsoluteMouseLocation
let mousePositionE = mousePositionB <@ tickE
mouseMovementE = mouseMovementB <@ tickE -- this yields flaky data
-- ... the rest of the network description left out ...
```

As explained above I'd like to express `mouseMovementE`

in terms of the `mousePositionB`

at current `tickE`

(known as `mousePositionE`

) and the `mousePositionE`

value at the previous `tickE`

.

Any help is greatly appreciated!

You are looking for `accumE`

which builds events from streams of events. I highly recommend reading the recursion section of the documentation which describes how it's implemented in terms of `stepper`

and `apply`

.

```
accumE :: MonadMoment m => a -> Event (a -> a) -> m (Event a)
-- starting value --^ | |
-- stream of events that modify it --^ |
-- resulting events --^
```

To compute the difference between two points with `accumE`

we'll need to keep track of the previous point. We'll also keep track of the current point. This will keep a little two-item history of the most recent events.

```
(Point V2 CInt , Point V2 CInt)
-- previous value, current value
edges :: MonadMoment m => a -> Event a -> m (Event (a, a))
edges initial later = accumE (initial, initial) (shift <$> later)
where
shift x2 (x0, x1) = (x1, x2)
```

To get the difference we'll subtract the previous one from the current one. This will give a complete network like

```
makeNetwork :: GraphicsData -> SDLEventSource -> MomentIO ()
makeNetwork gd sdlEventSource = mdo
tickE <- tickEvent sdlEventSource
mousePositionB <- fromPoll SDL.getAbsoluteMouseLocation
let mousePositionE = mousePositionB <@ tickE
mouseHistoryE <- edges zero mousePositionE
let mouseMovementE = (\(x0, x1) -> x1 ^-^ x0) <$> mouseHistoryE
-- ...
```

`zero`

and `^-^`

come from `Linear.Vector`

Asked in February 2016

Viewed 3,184 times

Voted 7

Answered 1 times

Viewed 3,184 times

Voted 7

Answered 1 times