Question

I am using Haskell to write a simple game / game-engine.

The following is one iteration of my game loop:

input <- getInput -- where input is some list of pressed keys
let world' = update world input
-- ... continue with the next iteration

The getInput function looks like:

getInput = do
    w <- getKey $ CharKey 'W'
    q <- getKey $ CharKey 'Q'
    -- ...
    return [("W", w), ...]

and the update function (inside the World.hs file) looks like:

update world input = world'
    where world' = -- if w, then do something, if q then do something, etc.

As you can see, my input logic is split between my actual Input.hs file and my World.hs file. The update function shouldn't really need to test for key press (in my opinion).

How do I split my input from my updating logic?


I am looking for something like callbacks, I suppose, which can be registered and unregistered at will. Registering moveForward to the key press of W would be ideal.

I have also looked into netwire - but I am having a hard time wrapping my head around functional reactive programming. If this is a case for FRP, I would appreciate any examples using it, as well.

Was it helpful?

Solution

You could declare an action as a function that transforms the world:

type Action = Word -> World

And then create actions for things independent of the keys to which you intend to bind them:

moveForward :: Action
moveForward world = ...

Then, you can pass a list of (key, action) pairs to a doInput function:

doInput :: [(CharKey, Action)] -> World -> IO World
doInput bindings world = foldM checkKey world bindings where
    checkKey world (key, action) = do
        pressed <- getKey key
        return $ if pressed then action world else world

So in your main loop, you can do something like:

mainloop world = do
    doRender world
    world' <- doInput [(CharKey 'W', moveForward)] world
    mainloop world'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top