Search code examples
haskell2d-games

What would be a typical game skeleton in Haskell


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.


Solution

  • 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