0

What would be the typical game skeleton for a Haskell game, let's say a simple shoot them up for instance? I am particularly interested on the data structure, and how to manage the update of all the elements in the world, in regards of immutability issue. Just saying that

  new_world=update_world(world)

is a little bit simplistic. For instance, how to deal with multiple interaction that can occurs between element of the world (collisions, reaction to player, etc....) especially when you have a lot of 'independent' elements impacted.

The main concern is about immutability of the world, which makes very difficult to update a "small" part of the world based on another subset of the world.

amalloy
  • 89,153
  • 8
  • 140
  • 205
tomsoft
  • 4,448
  • 5
  • 28
  • 35
  • 1
    curious to understand why the question has been downvoted without explaination! – tomsoft Sep 30 '14 at 11:58
  • Re:downvotes, This is either way too broad as a question about [2d-games] or about a more general problem which is badly hidden by unrelated cruft. I had hoped that beyond 1k rep one has learned enough about how good questions looked like. – Benjamin Bannier Sep 30 '14 at 12:31
  • 1
    @BenjaminBannier , the difficulty for haskell is to find real world examples beyond the obvious ones, especially on areas where OO approach seems to fit well (like 2D games). I've been through several discussion on the web about using haskell for games, which is highly debated, but all article are 3 to 5 years old. So it's not "how to write a 2D games using x/y language", but more "how haskell can (and must) be used in this specific contex" and what are the typical design pattern used in this case . – tomsoft Sep 30 '14 at 12:40
  • You need the State Monad or a similar structure at the top level, to save the scene. Thats the core of what you need. You could go a step further using the RWS Monad or just use a simple function you can call sequentially. `runWorld :: Event -> Scene -> (Raster,Scene)` . – vek Sep 30 '14 at 16:03

1 Answers1

4

I love gloss (gloss 2D library. it's very closed to your needs (I think)

A very simple example

import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game

-- Your app data
data App = App { mouseX :: Float
               , mouseY :: Float
               }

-- Draw world using your app data
      -- Here thing about *draw* your world (e.g. if radius > MAX then red else blue)
drawWorld (App mousex mousey) = color white $ circle mousex

-- Handle input events and update your app data
      -- Here thing about user interaction (e.g. when press button start jump!)
handleEvent
    (EventMotion (x, y)) -- current viewport mouse coordinates
    (App _ _) = App x y
handleEvent e w = w


-- Without input events you can update your world by time
     -- Here thing about time (e.g. if jumping use `t` to compute new position)
handleTime t w = w

runApp =
    play
        ( InWindow "Test" (300, 300) (0, 0) ) -- full screen or in window
        black                                 -- background color
        20                                    -- frames per second
        ( App 0 0 )                           -- your initial world
        drawWorld                             -- how to draw the world?
        handleEvent                           -- how app data is updated when IO events?
        handleTime                            -- how app data is updated along the time?

-- enjoy!
main = runApp

One simple example modifying some data structure (a list of circle radius) along the three event handlers (draw, input and time)

import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
import System.IO.Unsafe

data App = App { mouseX :: Float
               , mouseY :: Float
               , circleList :: [Float]
               , lastTime :: Float
               , currTime :: Float
               }

drawWorld app =
    color white $ pictures $ map circle $ circleList app

handleEvent
    (EventMotion (x, y)) -- current viewport mouse coordinates
    app = app { mouseX = x, mouseY = y,
                -- drop circles with radius > mouse **MOVED** position
                circleList = filter (<(abs x)) $ circleList app }
handleEvent e app = app

handleTime t app =
    app { currTime = currTime', lastTime = lastTime', circleList = circleList' }
    where currTime' = currTime app + t
          -- create new circle each 1 second
          createNew = currTime' - lastTime app > 1
          lastTime' = if createNew then currTime' else lastTime app
          -- each step, increase all circle radius
          circleList' = (if createNew then [0] else []) ++ map (+0.5) (circleList app)

runApp =
    play
        ( InWindow "Test" (300, 300) (0, 0) )
        black
        20
        ( App 0 0 [] 0 0 )
        drawWorld
        handleEvent
        handleTime

main = runApp

with result

enter image description here

josejuan
  • 9,338
  • 24
  • 31
  • Thanks for the answer, but it does not go to the details level where I think there is problem. Like how to update and manage a list of objects that might be interacting each others. I don't know a lot about haskell, but I am just trying to understand how to solve a relatively complex problem – tomsoft Sep 30 '14 at 11:56
  • _"What would be a typical game skeleton in Haskell"_ and you get it! :D `handleEvent` and `handleTime` are pure functions. You can update your world interactions here! – josejuan Sep 30 '14 at 11:59
  • I understand the handleTime, which is the obvious and easy part. What happens if during he handleTime update, a function needs to update a different element, or the player ship for instance – tomsoft Sep 30 '14 at 12:03
  • _"You need to loop"_ your question is not about _"game skeleton"_ is about data structures :D (e.g. http://en.wikipedia.org/wiki/K-d_tree ) – josejuan Sep 30 '14 at 12:07
  • In my view data structure seems to be fairly obvious (may be I am wrong). Which is less obvious is how to "update" different part of this structure in an effective manner without having to "pass" all the world to every function. I cam from an OO background, where the player can collide with a bullet object and being updated without having to know the complete world (it's again the world immutability which seems to me the biggest challenge) – tomsoft Sep 30 '14 at 12:12
  • _"how to "update" different part of this structure"_ ... about data structures (not game skeleton), in haskell you can update deep values on a big immutable structure in a efficient manner. Look for! ;) – josejuan Sep 30 '14 at 12:17
  • what are you talking of? I've been through http://stackoverflow.com/questions/7365425/is-there-a-haskell-idiom-for-updating-a-nested-data-structure and http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio , is this the kind of approach that should be used? – tomsoft Sep 30 '14 at 12:49
  • Yes but not only. These are about _"short accessors"_ (e.g. lens) but work with big data structures in Haskell is different than OO (usually). I suggest learn about trees, queues, zippers, `Data.Map`, ... and their CRUD related operations. Good luck! ;) – josejuan Sep 30 '14 at 13:00
  • @tomsoft There's always record syntax, but that can be a bit ugly at times. Lenses can be a nice approach. Here's an article that describes how to use lenses for this kind of thing http://www.haskellforall.com/2013/05/program-imperatively-using-haskell.html. – David Young Oct 01 '14 at 03:29