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.
Asked
Active
Viewed 631 times
1
-
1possible 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 Answers
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
-
Haskell newbie here, this helped me, thank you. I tried using hWaitForInput but getChar becomes blocking then, don't know why. – Miloslav Číž Jan 06 '17 at 18:27