Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Game loop in reactive-banana

View GameLoop.hs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
{------------------------------------------------------------------------------
reactive-banana
Implementation of an "industry strength" game loop with fixed time step
and variable fps.
See also http://gafferongames.com/game-physics/fix-your-timestep/
-------------------------------------------------------------------------------}
{-# LANGUAGE NoMonomorphismRestriction #-}
module Main where
 
import Reactive.Banana
 
{------------------------------------------------------------------------------
Game Loop
-------------------------------------------------------------------------------}
main = do
SDL.init [InitEverything]
SDL.setVideoMode 800 600 32 []
gamestate <- initGameState
Prelude.flip evalStateT gamestate gameLoop
return ()
 
 
-- timing helpers
fps = 30 -- physics framerate
dt = (1000 `div` fps) * ms -- physics timestep
 
 
type Duration = Integer
type Time = Integer
 
type GameNetworkDescription
= Event () -- ^ physics timer
-> Behavior Time -- ^ clock (synchronized with physics and user input)
-> Event Input -- ^ user input
-> NetworkDescription (Behavior (IO ())) -- ^ graphics to be sampled
 
gameLoop
:: Duration -- ^ physics time step
-> Double -- ^ maximal frames per second
-> GameNetworkDescription -- ^ event network corresponding to the game
-> IO ()
gameLoop dt maximalFps gameNetwork = do
-- set up event network
(ahInput , fireInput) <- newAddHandler
(ahPhysics , firePhysics) <- newAddHandler
(ahGraphics, fireGraphics) <- newAddHandler
clock <- newIORef 0
network <- compile $ do
eInput <- fromAddHandler ahInput
ePhysics <- fromAddHandler ahPhysics
bTime <- fromPoll (readIORef clock)
eGraphics <- fromAddHandler ahGraphics
bGraphics <- gameNetwork ePhysics bTime eInput
reactimate $ bGraphics <@ eGraphics
actuate network
-- game loop
go clock 0 =<< getRealTime
where
go clock acc old = do
-- acc accumulates excess time (usually < dt)
-- old keeps track of the time of the previous iteration of the game loop
input <- SDL.pollEvent
unless (event == Quit) $ do
new <- getRealTime
 
-- FIXME: set clock properly for user input
fireInput input -- handle user input
 
-- "physics" simulation
-- invariant: the world time begins at 0 and is always a multiple of dt
let (n,acc2) = (new - old + acc) `divMod` dt
replicateM_ (fromIntegral n) $ do
modifyIORef clock (+dt) -- update clock
firePhysics () -- handle physics
 
-- no need to hog all the CPU
-- FIXME: something with maximalFPS
SDL.delay (dt `div` 3)
 
-- graphics
-- note: time might *not* be multiple of dt, for interpolation
tempclock <- readIORef clock -- remember multiple of dt
modifyIORef clock (+acc2) -- advance clock slightly
fireGraphics () -- interpolate graphics
writeIORef clock tempclock -- reset clock to multiple of dt
 
go clock acc2 new
 
 
 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.