packages feed

pang-a-lambda-0.2.0.0: Experiments/stickyarrowup/Main.hs

{-# LANGUAGE Arrows #-}
import Graphics.UI.SDL            as SDL
import Graphics.UI.SDL.Primitives as SDL
import FRP.Yampa                  as Yampa
import Data.IORef
import Debug.Trace

width  = 640
height = 480

main = do
  timeRef <- newIORef (0 :: Int)
  reactimate initGraphs
             (\_ -> do
                dtSecs <- yampaSDLTimeSense timeRef
                return (dtSecs, Nothing))
             (\_ e -> display e >> return False)
             (fire (fromIntegral height / 2) (-10))

-- | Updates the time in an IO Ref and returns the time difference
updateTime :: IORef Int -> Int -> IO Int
updateTime timeRef newTime = do
  previousTime <- readIORef timeRef
  writeIORef timeRef newTime
  return (newTime - previousTime)

yampaSDLTimeSense :: IORef Int -> IO Yampa.DTime
yampaSDLTimeSense timeRef = do
  -- Get time passed since SDL init
  newTime <- fmap fromIntegral SDL.getTicks

  -- Obtain time difference
  dt <- updateTime timeRef newTime
  let dtSecs = fromIntegral dt / 100
  return dtSecs

initGraphs :: IO ()
initGraphs = do
  -- Initialise SDL
  SDL.init [InitVideo]

  -- Create window
  screen <- setVideoMode width height 16 [SWSurface]
  setCaption "Test" ""

display :: (Double, Double) -> IO()
display (boxY0,boxY) = do
  -- Obtain surface
  screen <- getVideoSurface

  -- Paint screen green
  let format = surfaceGetPixelFormat screen
  green <- mapRGB format 0 0xFF 0
  fillRect screen Nothing green

  -- Paint small red square, at an angle 'angle' with respect to the center
  red <- mapRGB format 0xFF 0xFF 0
  let x  = fromIntegral $ width `div` 2
      y0 = round boxY0
      y  = round boxY
  vLine screen x y0 y red

  -- Double buffering
  SDL.flip screen

rising :: Double -> Double -> SF () (Double, Double)
rising y0 v0 = proc () -> do
  y <- (y0+) ^<< integral -< v0
  returnA -< (y0, y)

fire :: Double -> Double -> SF () (Double, Double)
fire y vy = switch (rising y vy >>> (Yampa.identity &&& hitCeiling))
                   (\(y0, yn) -> switch (constant (y0, yn) &&& after 10 ())
                                        (\_ -> fire y vy))

hitCeiling :: SF (Double, Double) (Yampa.Event (Double, Double))
hitCeiling = arr (\(y0,y) ->
                   let boxTop = y
                   in if boxTop < 0
                        then Yampa.Event (y0, y)
                        else Yampa.NoEvent)