[Haskell-cafe] Observer pattern in haskell FRP
Heinrich Apfelmus
apfelmus at quantentunnel.de
Thu Nov 29 18:28:08 CET 2012
Nathan Hüsken wrote:
> Heinrich Apfelmus wrote:
>>
>> Personally, I would recommend is a complete change in perspective.
>>
>> The main idea of FRP is that it is a method to describe the evolution of
>> values in time. What is a game? It's just a picture that evolves in
>> time. The user can exert influence on the evolution by clicking certain
>> buttons on a mechanical device, but in the end, all he sees is a picture
>> that moves. [..]
>
> That perspective certainly make sense. But couldn't one also describe a
> game as a set of entities (spaceships) that react to the clicking of
> buttons?
Of course, generally speaking, you can describe it any way you like, FRP
is just a perspective, not a dictatorial doctrine.
But you probably mean that you want to describe spaceships within the
FRP perspective, though independent of how they are displayed. That's a
good point, which I missed. (The guideline of working backwards from the
very final result has served me very well when developing in FRP style,
though, hence my insistence on it.)
In the FRP perspective, I would use a slightly different language,
though. Namely, I would not say that spaceships are "entities that react
to button clicks", but rather that they are "represented by time-varying
positions that depend on past button clicks". The change is subtle but
important: you invert the direction of control. Instead of having a
button click do something to the spaceship ("push"), you have a
spaceship whose present position depends on past button clicks ("pull").
The FRP perspective is also more "holistic": you can think of a
spaceship and other time-varying values as if you knew their values for
all points in time, as if you were given graphical plots. (I have drawn
a few pretty pictures in the slides linked to here
<http://apfelmus.nfshost.com/blog/2012/07/15-frp-tutorial-slides.html>)
> If I take for example the breakout game from here [1]. It outputs an
> object "scene" of type Picture. But this picture is calculated from the
> objects "ballPos" and "paddlePos". So first a game state (ballPos,
> paddlePos) is created and than transformed to something renderable.
>
> I believe all examples I have seen for games with FRP follow this
> pattern, and I would I want to do is seperate the steps of calculating
> the game state and calculating the renderable from it.
In that light, the separation seems straightforward to me. Given the
time-varying values that represent game objects,
bSpaceShipPosition :: Behavior Position
bAsteroidPositions :: Behavior [Position]
bTime :: Behavior Time
you can transform and combine them into a graphic, for instance like this
bSpaceShipPicture :: Behavior Graphic
bSpaceShipPicture =
blinkenLights <$> bTime <*> bSpaceShipPosition
bAsteroidPictures = map drawAsteroid <$> bAsteroidPositions
bPicture = overlay <$>
((:) <$> bSpaceShipPicture <*> bAsteroidPictures)
In other words, you just combine old time-varying values into new ones,
much like you would combine combine graphical plots. Also note that you
can add animation a posteriori; it doesn't have to be part of the values
representing a space ship.
Of course, one important question is whether to represent asteroid
positions as a time-varying collection Behavior [Position] or as a
collection of time-varying values [Behavior Position] . The latter form
tends to require dynamic event switching, while the former form tends
towards a monolithic GameState value, which would forgo many of the
advantages of FRP.
I don't have enough practical experience to give a useful recommendation
here, but at the moment, I tend towards breaking it up as much as
possible, but trying to avoid dynamic event switching. My rule of thumb
is to model similar objects (asteroids) as a time-varying collection,
while modeling distinct objects (player space ship) as individual behaviors.
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
More information about the Haskell-Cafe
mailing list