
On 11/27/2012 07:12 AM, Ertugrul Söylemez wrote:
Nathan Hüsken
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