Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-11-26 22:17:33 GMT

Hey,
When writing games in other (imperative) languages, I like to separate
the game logic from the rendering. For this I use something similar to
the observer pattern.
With rendering I mean anything only related to how objects are drawn to
the screen. Animation state for example.
On my journey of exploring game programming with haskell (and FRP), I
wonder what a good way of archiving something similar would be.
If the rendering has no internal state, one can just write a function
draw :: GameLogicState -> IO ()
But when the rendering of an object has an internal state (e.g.
animation frame) than this is not possible.
Now I could write a Wire/Signal (whatever FRP implementation I use) that
translates to a RenderingState:
render :: Signal GameLogicState RenderingState
draw :: RenderingState -> IO ()
which is fine, except when my game is made of many objects.
Than I need to associate the state of one object in GameLogicState with
a sub-signal in render.
That could be done by giving every object an ID and letting
GameLogicState contain a map from IDs to ObjectLogicState.

which is fine, except when my game is made of many objects.
Than I need to associate the state of one object in GameLogicState with
a sub-signal in render.
That could be done by giving every object an ID and letting
GameLogicState contain a map from IDs to ObjectLogicState.

I fear that when I really have a lot of objects, assembling and
decomposing the map could become a major bottleneck.

So I am wondering: Is there (or can someone think of) a different
pattern by which this could be archived? Or asked different: How would
you do it?

Re: Observer pattern in haskell FRP

Ertugrul Söylemez <es <at> ertes.de>
2012-11-27 06:12:34 GMT

Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
> When writing games in other (imperative) languages, I like to separate
> the game logic from the rendering. For this I use something similar to
> the observer pattern.
>
> [...]
>
> So I am wondering: Is there (or can someone think of) a different
> pattern by which this could be archived? Or asked different: How would
> you do it?
That really depends on the FRP framework you are using. A framework can
be as simple as to model only the behaviors and events like the original
Fran, in which case often a design pattern such as the observer pattern
is not even available. One way out of this dilemma is that the main
behavior actually gives enough information to draw the scene.
In more versatile frameworks, which includes basically any modern
framework like Elerea, Netwire and reactive-banana, typically you would
model your entire application including the rendering as part of the
main behavior. In Netwire you can go as far as having something like
this:
myApp :: WireM IO a ()
However, I do not recommend this. As far as possible you should use a
stateless monad, ideally simply Identity or a reader:
type MyWire = WireM ((->) AppConfig)
myApp :: MyWire a GameFrame
This is only the first part of the story. The second part is the
rendering itself. You certainly want a way to make use of various
OpenGL extensions like vertex buffers, which are inherently stateful.
One sensible way I see is not to output the game's state, but rather a
state delta:
myApp :: MyWire a GameDelta
That way you can do the imperative stateful plumbing outside of the
application's wire and get the full power of FRP without giving up
efficient rendering. GameDelta itself would essentially be a type for
game state commands. In fact it could be a (free) monad:
myApp :: MyWire a (GameDelta ())
someDelta :: GameDelta ()
someDelta = do
randomPos <- liftA2 (,) getRandom getRandom
replicateM_ 4 (addCreature randomPos)
getPlayerPos >>= centerCamOver
Then you could perform that monadic action as part of the rendering
process.
Greets,
Ertugrul
--
--
Not to be or to be and (not to be or to be and (not to be or to be and
(not to be or to be and ... that is the list monad.

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-11-27 09:10:47 GMT

On 11/27/2012 07:12 AM, Ertugrul Söylemez wrote:
> Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
>
>> When writing games in other (imperative) languages, I like to separate
>> the game logic from the rendering. For this I use something similar to
>> the observer pattern.
>>
>> [...]
>>
>> So I am wondering: Is there (or can someone think of) a different
>> pattern by which this could be archived? Or asked different: How would
>> you do it?
>
> [...] As far as possible you should use a
> stateless monad, ideally simply Identity or a reader:
>
> type MyWire = WireM ((->) AppConfig)
>
> myApp :: MyWire a GameFrame
>
> This is only the first part of the story. The second part is the
> rendering itself. You certainly want a way to make use of various
> OpenGL extensions like vertex buffers, which are inherently stateful.
> One sensible way I see is not to output the game's state, but rather a
> state delta:
>
> myApp :: MyWire a GameDelta
>
> That way you can do the imperative stateful plumbing outside of the
> application's wire and get the full power of FRP without giving up
> efficient rendering. GameDelta itself would essentially be a type for
> game state commands. In fact it could be a (free) monad:
>
> myApp :: MyWire a (GameDelta ())
>
> someDelta :: GameDelta ()
> someDelta = do
> randomPos <- liftA2 (,) getRandom getRandom
> replicateM_ 4 (addCreature randomPos)
> getPlayerPos >>= centerCamOver
>
> Then you could perform that monadic action as part of the rendering
> process.
>
That sound like a good Idea. But I still have the problem of connection
"game logic" objects with "rendering" objects, or am I missing something?
Implementing "addCreature" is fine, but when I want a "removeCreature",
it has to remove the correct creature from a potentially very large
list/set of creatures.
How can I efficiently build this connections (which corresponds to a
pointer in other languages, I guess)?
Thanks!
Nathan

Re: Observer pattern in haskell FRP

Ertugrul Söylemez <es <at> ertes.de>
2012-11-27 10:36:58 GMT

Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
> > In fact it could be a (free) monad:
> >
> > myApp :: MyWire a (GameDelta ())
> >
> > someDelta :: GameDelta ()
> > someDelta = do
> > randomPos <- liftA2 (,) getRandom getRandom
> > replicateM_ 4 (addCreature randomPos)
> > getPlayerPos >>= centerCamOver
> >
> > Then you could perform that monadic action as part of the rendering
> > process.
>
> That sound like a good Idea. But I still have the problem of
> connection "game logic" objects with "rendering" objects, or am I
> missing something? Implementing "addCreature" is fine, but when I want
> a "removeCreature", it has to remove the correct creature from a
> potentially very large list/set of creatures.
> How can I efficiently build this connections (which corresponds to a
> pointer in other languages, I guess)?
That was a simplified example. In the real world it depends on what
generates your creatures. If they can be generated all over the code
then you need some form of identifier generation. This can be done by
the wire's underlying monad:
type Identifier = Int
type Game = WireM (StateT Identifier ((->) AppConfig))
A creature then may look something like this:
creature :: Game World (Creature, GameDelta ())
The wire produces a creating action at the first instant, then switches
to the creature's regular wire. The various GameDelta actions form at
least a monoid under (>>), and depending on your design even a group:
rec (creature1, gd1) <- creature -< w
(creature2, gd2) <- creature -< w
(creature3, gd3) <- creature -< w
w <- delay (World []) -< World [c1, c2, c3]
id -< (gd1 >> gd2 >> gd3)
That's the basic idea.
Greets,
Ertugrul
--
--
Not to be or to be and (not to be or to be and (not to be or to be and
(not to be or to be and ... that is the list monad.

Re: Observer pattern in haskell FRP

Nathan Hüsken wrote:
> Hey,
>
> When writing games in other (imperative) languages, I like to separate
> the game logic from the rendering. For this I use something similar to
> the observer pattern.
>
> With rendering I mean anything only related to how objects are drawn to
> the screen. Animation state for example.
>
> On my journey of exploring game programming with haskell (and FRP), I
> wonder what a good way of archiving something similar would be.
>
> [..]
>
> So I am wondering: Is there (or can someone think of) a different
> pattern by which this could be archived? Or asked different: How would
> you do it?
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.
How to describe picture that moves? Your large picture is probably made
from smaller pictures, for instance a small picture in the shape of
something we often call a "spaceship". So, you can implement a game by
describing the evolution of smaller pictures, and then combine these
into the description of a larger picture.
Now, the smaller pictures tend to have "hidden state", which means that
their future evolution depends a lot on the past evolution of the other
small pictures. In my experience with programming in FRP, it is very
useful to describe the individual pictures in terms of tiny state
machines and then connect these state machines via appropriate events
and behaviors to each other. The essence here is to decouple the
individual state machines from each other as much as possible and only
then to use the FRP abstractions to connect and combine them into a
"large emergent state machine".
(However, it is important to keep in mind that the fundamental
abstraction is not a state machine, but a time evolution that remembers
the past. This helps with embracing the new perspective and not
accidentally fall back to previous ways of thinking. Whether that ends
up with good code is up to you to find out, but if you decide to apply a
new perspective, it's best to do it in an extremist way to gain the
maximum benefit -- this benefit might certainly turn out to be zero, but
you will never find out if you wet your feet only a little bit.)
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-11-27 16:31:12 GMT

On 11/27/2012 04:18 PM, Heinrich Apfelmus wrote:
> Nathan Hüsken wrote:
>> Hey,
>>
>> When writing games in other (imperative) languages, I like to separate
>> the game logic from the rendering. For this I use something similar to
>> the observer pattern.
>>
>> With rendering I mean anything only related to how objects are drawn to
>> the screen. Animation state for example.
>>
>> On my journey of exploring game programming with haskell (and FRP), I
>> wonder what a good way of archiving something similar would be.
>>
>> [..]
>>
>> So I am wondering: Is there (or can someone think of) a different
>> pattern by which this could be archived? Or asked different: How would
>> you do it?
>
> 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.
>
> How to describe picture that moves? Your large picture is probably made
> from smaller pictures, for instance a small picture in the shape of
> something we often call a "spaceship". So, you can implement a game by
> describing the evolution of smaller pictures, and then combine these
> into the description of a larger picture.
>
> Now, the smaller pictures tend to have "hidden state", which means that
> their future evolution depends a lot on the past evolution of the other
> small pictures. In my experience with programming in FRP, it is very
> useful to describe the individual pictures in terms of tiny state
> machines and then connect these state machines via appropriate events
> and behaviors to each other. The essence here is to decouple the
> individual state machines from each other as much as possible and only
> then to use the FRP abstractions to connect and combine them into a
> "large emergent state machine".
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?
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.
> (However, it is important to keep in mind that the fundamental
> abstraction is not a state machine, but a time evolution that remembers
> the past. This helps with embracing the new perspective and not
> accidentally fall back to previous ways of thinking. Whether that ends
> up with good code is up to you to find out, but if you decide to apply a
> new perspective, it's best to do it in an extremist way to gain the
> maximum benefit -- this benefit might certainly turn out to be zero, but
> you will never find out if you wet your feet only a little bit.)
That certainly makes sense, and it is also very difficult for me to
stick to the "FRP perspective".
But I do not see that seperating rendering and game logic code goes
against the FRP perspective.
Best Regards,
Nathan
[1] https://github.com/bernstein/breakout/blob/master/src/Main.hs
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

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
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-12-06 18:23:20 GMT

Sorry for the late reply, I somehow missed this eMail ...
On 11/29/2012 06:28 PM, Heinrich Apfelmus wrote:
>> 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.
>
Yes, but these examples are extremely simple. The animation has no
internal "state". What if every Asteroid also has a animation state
(which I would want to add a posteriori) and can be destroyed.
Than the connection between the asteroids "game logic" value, and
"rendering" value needs some kind of bookkeeping to be maintained.
>
> 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.
>
Thank you for your input!
Regards,
Nathan

Re: Observer pattern in haskell FRP

Nathan Hüsken wrote:
> Heinrich Apfelmus wrote:
>>
>> 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.
>>
> Yes, but these examples are extremely simple. The animation has no
> internal "state". What if every Asteroid also has a animation state
> (which I would want to add a posteriori) and can be destroyed.
> Than the connection between the asteroids "game logic" value, and
> "rendering" value needs some kind of bookkeeping to be maintained.
Fair enough, but I don't see how this can be fitted into a general
pattern. If the animation "state" is coupled tightly to the game logic
"state", then the question whether the animation is part of the game
logic or not does not have a clear answer anymore. Hm.
You mentioned that in an imperative setting, you would use something
similar to the observer pattern. Judging from the wikipedia page
<http://en.wikipedia.org/wiki/Observer_pattern>, it seems to me that
this is just the Event type, though, so I don't understand how this
helps with the problem at hand.
Maybe discussing a concrete example could be very helpful. Could you
give a minimal example that still contains the key difficulties? Maybe a
collection of asteroids that float in space, can be added or removed
with a button click and who are animated as rotating rocks, all starting
in a certain position when they are created? How would you use the
observer pattern in this case?
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-12-10 15:28:37 GMT

On 12/08/2012 10:32 AM, Heinrich Apfelmus wrote:
> Nathan Hüsken wrote:
>> Heinrich Apfelmus wrote:
>>>
>>> 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.
>>>
>> Yes, but these examples are extremely simple. The animation has no
>> internal "state". What if every Asteroid also has a animation state
>> (which I would want to add a posteriori) and can be destroyed.
>> Than the connection between the asteroids "game logic" value, and
>> "rendering" value needs some kind of bookkeeping to be maintained.
>
> Fair enough, but I don't see how this can be fitted into a general
> pattern. If the animation "state" is coupled tightly to the game logic
> "state", then the question whether the animation is part of the game
> logic or not does not have a clear answer anymore. Hm.
I see it like this: The "logic state" may not depend on the "rendering
state". If for example the animation of an asteroid changes how or when
objects collide with it, than the animation is part of the logic.
If however the physics of the game treat the asteroid as a object whose
shape does not change depending in the animation, than the animation is
part of the "rendering state".
So the coupling may only be logic->rendering.
> You mentioned that in an imperative setting, you would use something
> similar to the observer pattern. Judging from the wikipedia page
> <http://en.wikipedia.org/wiki/Observer_pattern>, it seems to me that
> this is just the Event type, though, so I don't understand how this
> helps with the problem at hand.
Yes, you are right. The problem at hand is something one has to deal
with when using the observer pattern. Only in C++ I do not find it hard
to do.
> Maybe discussing a concrete example could be very helpful. Could you
> give a minimal example that still contains the key difficulties? Maybe a
> collection of asteroids that float in space, can be added or removed
> with a button click and who are animated as rotating rocks, all starting
> in a certain position when they are created? How would you use the
> observer pattern in this case?
I put a pseudo C++ example below the mail. I use the terms "model" and
"view" for the game logic and rendering respectively.
The example is a little different. Asteroids explode when they collide.
The moment asteroids explode, they are removed from the model (the game
logic) while in the view (rendering) they still exist until the
explosion animation is over.
As you said, this basically is sending messages from the Model (in the
observer pattern called Observable) to the view (Observer). The main
difficulty I have is how to send the messages from the correct model to
the correct view.
In C++ this is done by keeping pointers.
Simply assigning IDs would work, but than I would have to always pass a
map from the model to the view, and I feel like (also I have little
experience with this), that this approach is not very scalable.
Best Regards,
Nathan
===========
The C++ example, its not complete, but I believe it captures the idea.
class GalaxyModel {
GalaxyView* view;
list<AsteroidModel> asteroids;
void addAsteroid(Position pos) {
asteroids.push(AsteroidModel(pos));
view->onNewAsteroid(asteroids.back());
}
void update() {
for (a in asteroids) {
a.update();
}
for(a in asteroids) {
for (b in asteroids) {
if (collide(a,b)) {
a.explode();
b.explode();
asteroids.remove(a);
asteroids.remove(b);
}
}
}
}
};
class AsteroidModel {
AsteroidView* view;
Position pos;
update() {
updatePosition();
view->onNewPos(pos);
}
explode() {
view->onExplode();
}
};
class GalaxyView {
list<AstroidView> asteroids;
void onNewAsteroid(AsteroidModel* model) {
asteroids.push(AsteroidView(model));
}
void update() {
for (a in asteroids) {
a.update();
if (a.dead) asteroids.remove(a);
}
}
}
class AsteroidView {
float rotation;
bool dead = false;
void onExplode() {
setExplodeAnimation();
}
void onNewPos() { //Store position}
void update() {
rotation += 1.0;
if (explodeAnimationOver()) {
m_dead = true;
}
}
}
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

Ertugrul Söylemez <es <at> ertes.de>
2012-12-10 15:56:51 GMT

Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
> I put a pseudo C++ example below the mail. I use the terms "model" and
> "view" for the game logic and rendering respectively.
> The example is a little different. Asteroids explode when they
> collide. The moment asteroids explode, they are removed from the model
> (the game logic) while in the view (rendering) they still exist until
> the explosion animation is over.
>
> As you said, this basically is sending messages from the Model (in the
> observer pattern called Observable) to the view (Observer). The main
> difficulty I have is how to send the messages from the correct model
> to the correct view.
> In C++ this is done by keeping pointers.
> Simply assigning IDs would work, but than I would have to always pass
> a map from the model to the view, and I feel like (also I have little
> experience with this), that this approach is not very scalable.
Actually it is very scalable, as the same map is passed to every object.
It can even live in the underlying monad, which means that you could
even use a mutable vector, if you wish; however, I don't recommend that.
Remember that a map is immutable and shared, so passing the same map to
multiple objects is in fact the same as passing a pointer in C++.
Lookups in and updates to the map are of logarithmic complexity, so this
scales well. Only doubling the number of nodes actually adds one full
step to lookups and updates.
If you're dealing with millions of objects you may want to use the
vector solution mentioned earlier. This requires an imperative
underlying monad, but you would get about the same speed as in C++.
Greets,
Ertugrul
--
--
Not to be or to be and (not to be or to be and (not to be or to be and
(not to be or to be and ... that is the list monad.

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-12-11 15:08:43 GMT

Am 10.12.2012 16:56, schrieb Ertugrul Söylemez:
> Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
>
>> I put a pseudo C++ example below the mail. I use the terms "model" and
>> "view" for the game logic and rendering respectively.
>> The example is a little different. Asteroids explode when they
>> collide. The moment asteroids explode, they are removed from the model
>> (the game logic) while in the view (rendering) they still exist until
>> the explosion animation is over.
>>
>> As you said, this basically is sending messages from the Model (in the
>> observer pattern called Observable) to the view (Observer). The main
>> difficulty I have is how to send the messages from the correct model
>> to the correct view.
>> In C++ this is done by keeping pointers.
>> Simply assigning IDs would work, but than I would have to always pass
>> a map from the model to the view, and I feel like (also I have little
>> experience with this), that this approach is not very scalable.
> Actually it is very scalable, as the same map is passed to every object.
> It can even live in the underlying monad, which means that you could
> even use a mutable vector, if you wish; however, I don't recommend that.
>
> Remember that a map is immutable and shared, so passing the same map to
> multiple objects is in fact the same as passing a pointer in C++.
> Lookups in and updates to the map are of logarithmic complexity, so this
> scales well. Only doubling the number of nodes actually adds one full
> step to lookups and updates.
>
> If you're dealing with millions of objects you may want to use the
> vector solution mentioned earlier. This requires an imperative
> underlying monad, but you would get about the same speed as in C++.
>
I might just not be used enough to functional data structures, "Purely
functional data structures" is on my reading list :).
I was thinking, in the asteroids example the only reason why the view
needs more input than the models output, is that it needs to be informed
of creation and destruction of asteroids.
So, in the model one could habe a signal
asteroidsModel :: Signal Input [Just AsteroidModel]
which outputs "Nothing" for asteroids that have been destroyed.
Then, in the view this would be taken for as input for
asteroidsView :: Signal [Just AsteroidModel] [Picture]
asteroidsView would have to do the following:
* route the input list to a list of "asteroidView" signals.
* When there is a "Nothing" in the input list, the corresponding (now
exploding) view is moved to a list of "zombie asteroids" where it
remains until its explosion animation is over.
* When the input list is longer than the list of current astroidView
signals, the list is extended.
This would avoid the need for bookkeeping ids.
Regards,
Nathan

Re: Observer pattern in haskell FRP

Ertugrul Söylemez <es <at> ertes.de>
2012-12-12 00:26:33 GMT

Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
> > Actually it is very scalable, as the same map is passed to every
> > object. It can even live in the underlying monad, which means that
> > you could even use a mutable vector, if you wish; however, I don't
> > recommend that.
> >
> > Remember that a map is immutable and shared, so passing the same map
> > to multiple objects is in fact the same as passing a pointer in
> > C++. Lookups in and updates to the map are of logarithmic
> > complexity, so this scales well. Only doubling the number of nodes
> > actually adds one full step to lookups and updates.
> >
> > If you're dealing with millions of objects you may want to use the
> > vector solution mentioned earlier. This requires an imperative
> > underlying monad, but you would get about the same speed as in C++.
>
> I might just not be used enough to functional data structures, "Purely
> functional data structures" is on my reading list :).
>
> I was thinking, in the asteroids example the only reason why the view
> needs more input than the models output, is that it needs to be
> informed of creation and destruction of asteroids.
Why would the view need to be informed?
> So, in the model one could habe a signal
>
> asteroidsModel :: Signal Input [Just AsteroidModel]
>
> which outputs "Nothing" for asteroids that have been destroyed.
> Then, in the view this would be taken for as input for
>
> asteroidsView :: Signal [Just AsteroidModel] [Picture]
>
> asteroidsView would have to do the following:
> * route the input list to a list of "asteroidView" signals.
> * When there is a "Nothing" in the input list, the corresponding (now
> exploding) view is moved to a list of "zombie asteroids" where it
> remains until its explosion animation is over.
> * When the input list is longer than the list of current astroidView
> signals, the list is extended.
>
> This would avoid the need for bookkeeping ids.
This is a very complicated way to do it. I would simply regard the
"zombie asteroids" as regular objects. That way you don't need a
special case in the view.
Greets,
Ertugrul
--
--
Not to be or to be and (not to be or to be and (not to be or to be and
(not to be or to be and ... that is the list monad.

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-12-13 00:09:30 GMT

On 12/12/2012 01:26 AM, Ertugrul Söylemez wrote:
> Nathan Hüsken <nathan.huesken <at> posteo.de> wrote:
>
>>> Actually it is very scalable, as the same map is passed to every
>>> object. It can even live in the underlying monad, which means that
>>> you could even use a mutable vector, if you wish; however, I don't
>>> recommend that.
>>>
>>> Remember that a map is immutable and shared, so passing the same map
>>> to multiple objects is in fact the same as passing a pointer in
>>> C++. Lookups in and updates to the map are of logarithmic
>>> complexity, so this scales well. Only doubling the number of nodes
>>> actually adds one full step to lookups and updates.
>>>
>>> If you're dealing with millions of objects you may want to use the
>>> vector solution mentioned earlier. This requires an imperative
>>> underlying monad, but you would get about the same speed as in C++.
>>
>> I might just not be used enough to functional data structures, "Purely
>> functional data structures" is on my reading list :).
>>
>> I was thinking, in the asteroids example the only reason why the view
>> needs more input than the models output, is that it needs to be
>> informed of creation and destruction of asteroids.
>
> Why would the view need to be informed?
So that the coresponding view objects can be removed (imidiatly or at
some later point).
>
>
>> So, in the model one could habe a signal
>>
>> asteroidsModel :: Signal Input [Just AsteroidModel]
>>
>> which outputs "Nothing" for asteroids that have been destroyed.
>> Then, in the view this would be taken for as input for
>>
>> asteroidsView :: Signal [Just AsteroidModel] [Picture]
>>
>> asteroidsView would have to do the following:
>> * route the input list to a list of "asteroidView" signals.
>> * When there is a "Nothing" in the input list, the corresponding (now
>> exploding) view is moved to a list of "zombie asteroids" where it
>> remains until its explosion animation is over.
>> * When the input list is longer than the list of current astroidView
>> signals, the list is extended.
>>
>> This would avoid the need for bookkeeping ids.
>
> This is a very complicated way to do it. I would simply regard the
> "zombie asteroids" as regular objects. That way you don't need a
> special case in the view.
I was thinking by doing it this way I could completely avoid the need
for ids by this the bookkeeping of ids.
On the other hand, I might need the ids anyway for other things and than
my approach would just add complexity, as you said.
Regards,
Nathan

Re: Observer pattern in haskell FRP

Nathan Hüsken wrote:
> On 12/08/2012 10:32 AM, Heinrich Apfelmus wrote:
>> Fair enough, but I don't see how this can be fitted into a general
>> pattern. If the animation "state" is coupled tightly to the game logic
>> "state", then the question whether the animation is part of the game
>> logic or not does not have a clear answer anymore. Hm.
>
> I see it like this: The "logic state" may not depend on the "rendering
> state". If for example the animation of an asteroid changes how or when
> objects collide with it, than the animation is part of the logic.
> If however the physics of the game treat the asteroid as a object whose
> shape does not change depending in the animation, than the animation is
> part of the "rendering state".
> So the coupling may only be logic->rendering.
>
>> Maybe discussing a concrete example could be very helpful. Could you
>> give a minimal example that still contains the key difficulties?
>
> I put a pseudo C++ example below the mail. I use the terms "model" and
> "view" for the game logic and rendering respectively.
> The example is a little different. Asteroids explode when they collide.
> The moment asteroids explode, they are removed from the model (the game
> logic) while in the view (rendering) they still exist until the
> explosion animation is over.
(Sorry for the late reply.)
I see, that's a nice example.
Indeed, if you try to model this situation with dynamic collections
galaxyModel :: Behavior [AsteroidModel]
galaxyView :: Behavior [AsteroidView]
then you have to keep track of IDs in some way, because a change in the
collection of asteroid models needs to be reflected in a corresponding
change in the collection of asteroid views.
identifier :: AsteroidModel -> ID
eCollisions :: Event [ID]
eCollisions = collisions <$> galaxyModel < <at> eTick
where
collisions asteroids = [identifier a | a <- asteroids,
b <- asteroids, a `collides` b]
galaxyModel = accumB initialAsteroidModels
$ removeFromList <$> eCollisions
galaxyView = accumB initialAsteroidViews
$ startExplosions <$> eCollisions
That said, do note that any significant use of pointers in an imperative
program translates to the use of identifiers in the purely functional
variant. This is very much *independent* of FRP! In other words, if you
find that giving certain game objects an "identity" is a good way to
structure your code, then you need to use identifiers, regardless of
whether you use FRP or not.
Of course, as you note in another message, there are other ways to
structure this code. For instance, the second idea would be to use a
data type
type Asteroid = (Maybe AsteroidModel, AsteroidView)
which represents live asteroids as (Just positionEtc, view) and dead
asteroids as (Nothing, explosionView) . Then again, one unsatisfactory
point about this approach is that an exploding asteroid is now
represented explicitly in the game logic as a Nothing value.
A third approach would be to keep an explicit list of explosions.
data AsteroidModel =
AsteroidModel { view :: AsteroidView, pos :: Position }
data AsteroidView =
AsteroidView { rotation :: Angle }
data Explosion =
Explosion { posExp :: Position }
galaxyView :: Behavior ([AsteroidView], [Explosion])
galaxyView = (,) <$> (map view <$> galaxyModel) <$> explosions
explosions = accumB [] $ startExplosions <$> eCollisions
You do need an event to communicate which asteroids have exploded, but
an exploding asteroid will not appear in galaxyModel anymore. Instead,
it will be added as an "anonymous" explosion to the rendering logic. (In
a sense, the asteroid views with the state variables dead = false and
dead = true have been split into different types.)
I find the third approach to be quite satisfactory. What is your opinion?
The more I think about this example, the more I think that the
underlying difficulty is not FRP, but the use of pointers / identities.
Best regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

Nathan Hüsken <nathan.huesken <at> posteo.de>
2012-12-19 17:22:17 GMT

On 12/18/2012 10:52 PM, Heinrich Apfelmus wrote:
> Nathan Hüsken wrote:
>> On 12/08/2012 10:32 AM, Heinrich Apfelmus wrote:
>>> Fair enough, but I don't see how this can be fitted into a general
>>> pattern. If the animation "state" is coupled tightly to the game logic
>>> "state", then the question whether the animation is part of the game
>>> logic or not does not have a clear answer anymore. Hm.
>>
>> I see it like this: The "logic state" may not depend on the "rendering
>> state". If for example the animation of an asteroid changes how or when
>> objects collide with it, than the animation is part of the logic.
>> If however the physics of the game treat the asteroid as a object whose
>> shape does not change depending in the animation, than the animation is
>> part of the "rendering state".
>> So the coupling may only be logic->rendering.
>>
>>> Maybe discussing a concrete example could be very helpful. Could you
>>> give a minimal example that still contains the key difficulties?
>>
>> I put a pseudo C++ example below the mail. I use the terms "model" and
>> "view" for the game logic and rendering respectively.
>> The example is a little different. Asteroids explode when they collide.
>> The moment asteroids explode, they are removed from the model (the game
>> logic) while in the view (rendering) they still exist until the
>> explosion animation is over.
>
> (Sorry for the late reply.)
>
> I see, that's a nice example.
>
> Indeed, if you try to model this situation with dynamic collections
>
> galaxyModel :: Behavior [AsteroidModel]
> galaxyView :: Behavior [AsteroidView]
>
> then you have to keep track of IDs in some way, because a change in
> the collection of asteroid models needs to be reflected in a
> corresponding change in the collection of asteroid views.
>
> identifier :: AsteroidModel -> ID
>
> eCollisions :: Event [ID]
> eCollisions = collisions <$> galaxyModel < <at> eTick
> where
> collisions asteroids = [identifier a | a <- asteroids,
> b <- asteroids, a `collides` b]
>
> galaxyModel = accumB initialAsteroidModels
> $ removeFromList <$> eCollisions
>
> galaxyView = accumB initialAsteroidViews
> $ startExplosions <$> eCollisions
>
>
> That said, do note that any significant use of pointers in an
> imperative program translates to the use of identifiers in the purely
> functional variant. This is very much *independent* of FRP! In other
> words, if you find that giving certain game objects an "identity" is a
> good way to structure your code, then you need to use identifiers,
> regardless of whether you use FRP or not.
Well, direct translation of imperative structures are probably often not
a smart way to go. Instead a functional approach with the same benefits
is more desirable. I just find it very hard to think in new directions
for a problem I already know a solution in an imperative style :).
> Of course, as you note in another message, there are other ways to
> structure this code. For instance, the second idea would be to use a
> data type
>
> type Asteroid = (Maybe AsteroidModel, AsteroidView)
>
> which represents live asteroids as (Just positionEtc, view) and dead
> asteroids as (Nothing, explosionView) . Then again, one
> unsatisfactory point about this approach is that an exploding asteroid
> is now represented explicitly in the game logic as a Nothing value.
>
>
> A third approach would be to keep an explicit list of explosions.
>
> data AsteroidModel =
> AsteroidModel { view :: AsteroidView, pos :: Position }
> data AsteroidView =
> AsteroidView { rotation :: Angle }
> data Explosion =
> Explosion { posExp :: Position }
>
> galaxyView :: Behavior ([AsteroidView], [Explosion])
> galaxyView = (,) <$> (map view <$> galaxyModel) <$> explosions
>
> explosions = accumB [] $ startExplosions <$> eCollisions
>
> You do need an event to communicate which asteroids have exploded, but
> an exploding asteroid will not appear in galaxyModel anymore.
> Instead, it will be added as an "anonymous" explosion to the rendering
> logic. (In a sense, the asteroid views with the state variables dead
> = false and dead = true have been split into different types.)
>
>
> I find the third approach to be quite satisfactory. What is your opinion?
I agree, I like it!
> The more I think about this example, the more I think that the
> underlying difficulty is not FRP, but the use of pointers / identities.
I think the original question where I was asking for replacement pattern
for observers in FRP is the wrong way to go.
The goal was to separate game logic and rendering logic, and the
solutions you mention provide this.
Other Problems that are solved with the Observer Pattern probably should
have a completely different approach in function programming or FRP.
I am very happy with all he replies I got in this thread and I will see
where it gets me.
Thanks!
Nathan
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Re: Observer pattern in haskell FRP

serialhex <serialhex <at> gmail.com>
2012-12-19 21:40:04 GMT

hey all, i've been lurking in this thread for a bit & i just found this interesting article from chris granger (yeah, the light table guy). he just completed the node knockout they had recently & decided to make a game. he did it all in clojurescript & he discusses some aspects of programming a game in a functional language. so maybe this will give you some ideas on how to write games in haskell.

-- * If God had a beard, he'd be a UNIX programmer.* Some people pray for more than they are willing to work for.* This is Linux. Distro is a proper subset of Settings. --TwilightXaos on slashdot
---CFO: “What happens if we train people and they leave?”CTO: “What if we don’t and they stay?”