1

http://pastebin.com/2CS1k1Zq

In this game i need to get step the game forward every half a second or so while occasionally getting input to change direction. These too things seem impossible to do with haskell is there a way to do it? Currently I am having an mv tread stall exception.

Kyle McKean
  • 445
  • 2
  • 11
  • 1
    possible duplicate of [How do I write a game loop in Haskell?](http://stackoverflow.com/questions/19285691/how-do-i-write-a-game-loop-in-haskell) – Rein Henrichs Nov 21 '14 at 16:43
  • No because I understand the basics of how to make a gameloop what i dont understand is how you delay your game or make it step through in time. Also how to get input. – Kyle McKean Nov 21 '14 at 16:54
  • You're probably going to need an observer to check for keydowns. How to do it depends on your platform, you might need to do some "FFI-ing". Once that's covered, your actual game loop could look like a standard Haskell game loop. And to make it playable, don't forget to delay the rendering part (e.g. make the thread sleep between game-steps, but make sure you can still get input!). It would be helpful if you could mention your platform and even tag it (especially since this seems to be a console game). – MasterMastic Nov 21 '14 at 17:10
  • What is FFL ing? And i am running on a windows machine – Kyle McKean Nov 21 '14 at 18:35
  • I mean using the FFI (Foreign Function Interface). I suggest you learn what it is (within Haskell, of course). You could use it to import (impure) system calls (e.g. from the Win32 API) that will tell you when a key is pressed. – MasterMastic Nov 21 '14 at 19:31
  • @KyleMcKean By the way, when you're responding to someone in a comment that isn't to his question or answer, make sure to tag his name with a "@", like I did at the start of this comment. This will notify the person that you replied. So in this particular comment this isn't necessary because this is a comment to your question (but I did for demonstration). – MasterMastic Nov 21 '14 at 20:00
  • Sounds like this answer is relevant: http://stackoverflow.com/questions/9143041/block-until-keypress-or-given-time-of-day – ErikR Nov 21 '14 at 21:07

1 Answers1

2

Update: Found the hWaitForInput function in System.IO which is essentially the same as waitFor.

Here is some code largely based on this answer.

The main difference I made is that the thread waiting for a key press does not perform the getChar directly. The result communicated in the MVar is an indication of timeout or that a key press has occurred. It is the responsibility of the main thread to actually get the character. This prevents a possible race condition in case the char reading thread is killed between getting the character and putting it into the MVar.

import Control.Concurrent
import Control.Monad
import Data.Maybe
import System.IO
import Control.Exception

data Event = CharReady | TimedOut

withRawStdin :: IO a -> IO a
withRawStdin = bracket uncook restore . const
  where
    uncook = do
        oldBuffering <- hGetBuffering stdin
        oldEcho <- hGetEcho stdin
        hSetBuffering stdin NoBuffering
        hSetEcho stdin False
        return (oldBuffering, oldEcho)
    restore (oldBuffering, oldEcho) = do
        hSetBuffering stdin oldBuffering
        hSetEcho stdin oldEcho

waitFor :: Int -> IO Event
waitFor delay = do
    done <- newEmptyMVar
    withRawStdin . bracket (start done) cleanUp $ \_ -> takeMVar done
  where
    start done = do
        t1 <- forkIO $ hLookAhead stdin >> putMVar done CharReady
        t2 <- forkIO $ threadDelay delay >> putMVar done TimedOut
        return (t1, t2)
    cleanUp (t1, t2) = do
        killThread t1
        killThread t2

loop state = do
  if state <= 0
    then putStrLn "Game over."
    else do putStrLn $ "Rounds to go: " ++ show state
            e <- waitFor 3000000
            case e of
              TimedOut -> do putStrLn "Too late!"; loop state
              CharReady -> do c <- getChar -- should not block
                              if c == 'x'
                                then do putStrLn "Good job!"; loop (state-1)
                                else do putStrLn "Wrong key"; loop state

main = loop 3
Community
  • 1
  • 1
ErikR
  • 51,541
  • 9
  • 73
  • 124