Use state monad to hold main loop state

This commit is contained in:
Matthias Schiffer 2010-02-23 23:31:11 +01:00
parent 366eb711dd
commit 9036ac3105
3 changed files with 62 additions and 25 deletions

View file

@ -1,6 +1,7 @@
{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-} {-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}
module GLDriver ( Driver(..) module GLDriver ( Driver(..)
, SomeDriver(..)
, Event , Event
, SomeEvent(..) , SomeEvent(..)
, QuitEvent(..) , QuitEvent(..)
@ -21,6 +22,15 @@ class Driver a where
nextEvent :: a -> IO (Maybe SomeEvent) nextEvent :: a -> IO (Maybe SomeEvent)
data SomeDriver = forall d. Driver d => SomeDriver d
instance Driver SomeDriver where
initialized (SomeDriver d) = initialized d
initGL (SomeDriver d) = initGL d >>= return . SomeDriver
deinitGL (SomeDriver d) = deinitGL d
swapBuffers (SomeDriver d) = swapBuffers d
nextEvent (SomeDriver d) = nextEvent d
class Typeable a => Event a class Typeable a => Event a

View file

@ -1,4 +1,4 @@
{-# LANGUAGE PatternGuards #-} {-# LANGUAGE PatternGuards, GeneralizedNewtypeDeriving #-}
import Game import Game
import Level import Level
@ -14,45 +14,66 @@ import Data.Maybe
import System.Time import System.Time
data MainState = MainState
{ driver :: !SomeDriver
, time :: !ClockTime
}
newtype MainT m a = MainT (StateT MainState m a)
deriving (Monad, MonadState MainState, MonadIO, MonadTrans)
type Main = MainT Game
runMain :: MainState -> Main a -> Game (a, MainState)
runMain st (MainT a) = runStateT a st
main :: IO () main :: IO ()
main = do main = do
gl <- initGL glxDriver gl <- initGL glxDriver
let gameState = GameState {level = testLevel, tanks = [Tank 0.5 0.5 0]}
when (initialized gl) $ do when (initialized gl) $ do
time <- getClockTime clockTime <- getClockTime
let mainState = MainState {driver = SomeDriver gl, time = clockTime}
gameState = GameState {level = testLevel, tanks = [Tank 0.0 0.0 0]}
setup 800 600 setup 800 600
runGame gameState $ mainLoop gl time runGame gameState $ runMain mainState $ mainLoop
deinitGL gl deinitGL gl
minFrameTime :: Integer minFrameTime :: Integer
minFrameTime = 10000 minFrameTime = 10
mainLoop :: Driver a => a -> ClockTime -> Game () mainLoop :: Main ()
mainLoop gl time = do mainLoop = do
gl <- gets driver
t <- gets time
run <- liftIO $ handleEvents gl run <- liftIO $ handleEvents gl
render lift render
liftIO $ swapBuffers gl liftIO $ swapBuffers gl
newTime <- liftIO getClockTime newTime <- liftIO getClockTime
let td = timeDiff newTime time let td = timeDiff newTime t
when (td < minFrameTime) $ when (td < minFrameTime) $
liftIO $ threadDelay $ fromIntegral (minFrameTime - td) liftIO $ threadDelay $ fromIntegral $ 1000*(minFrameTime - td)
newTime <- liftIO getClockTime newTime <- liftIO getClockTime
let td = timeDiff newTime t
--liftIO $ print $ timeDiff newTime time lift $ modify $ \state -> state {tanks = (Tank ((posx . head . tanks $ state)+0.0001*(fromIntegral td)) 0.0 0):(tail . tanks $ state)}
when run $ mainLoop gl newTime --liftIO $ print $ timeDiff newTime t
modify $ \state -> state {time = newTime}
when run $ mainLoop
timeDiff :: ClockTime -> ClockTime -> Integer timeDiff :: ClockTime -> ClockTime -> Integer
timeDiff (TOD s1 ps1) (TOD s2 ps2) = (s1-s2)*1000000 + (ps1-ps2)`div`1000000 timeDiff (TOD s1 ps1) (TOD s2 ps2) = (s1-s2)*1000 + (ps1-ps2)`div`1000000000
handleEvents :: Driver a => a -> IO Bool handleEvents :: Driver a => a -> IO Bool
@ -66,8 +87,8 @@ handleEvents gl = do
handleEvent :: SomeEvent -> IO Bool handleEvent :: SomeEvent -> IO Bool
handleEvent ev handleEvent ev
| Just QuitEvent <- fromEvent ev = return False
| Just (ResizeEvent w h) <- fromEvent ev = do | Just (ResizeEvent w h) <- fromEvent ev = do
resize w h resize w h
return True return True
| Just QuitEvent <- fromEvent ev = return False
| otherwise = return True | otherwise = return True

View file

@ -5,6 +5,7 @@ module Render ( setup
import Game import Game
import Tank
import Control.Monad.State import Control.Monad.State
@ -16,7 +17,8 @@ import Graphics.Rendering.OpenGL.GL.VertexSpec
setup :: Int -> Int -> IO () setup :: Int -> Int -> IO ()
setup = resize setup w h = do
resize w h
resize :: Int -> Int -> IO () resize :: Int -> Int -> IO ()
resize w h = do resize w h = do
@ -34,11 +36,15 @@ resize w h = do
render :: Game () render :: Game ()
render = liftIO $ do render = do
tank <- liftM head $ gets tanks
let x = posx tank
y = posy tank
liftIO $ do
clear [ColorBuffer] clear [ColorBuffer]
renderPrimitive Triangles $ do renderPrimitive Triangles $ do
vertex $ Vertex2 (-0.5 :: GLfloat) (0.5 :: GLfloat) vertex $ Vertex2 (x-0.5 :: GLfloat) (y+0.5 :: GLfloat)
vertex $ Vertex2 (0.5 :: GLfloat) (0.5 :: GLfloat) vertex $ Vertex2 (x+0.5 :: GLfloat) (y+0.5 :: GLfloat)
vertex $ Vertex2 (0.5 :: GLfloat) (-0.5 :: GLfloat) vertex $ Vertex2 (x+0.5 :: GLfloat) (y-0.5 :: GLfloat)