{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
import Graphics.UI.SDL as SDL
import Graphics.UI.SDL.Primitives as SDL
import FRP.Yampa as Yampa
import Data.IORef
import FRP.Titan.Debug.Core
import FRP.Titan.Debug.CommTCP
width :: Num a => a
width = 640
height :: Num a => a
height = 480
main = do
timeRef <- newIORef (0 :: Int)
bridge <- mkTitanCommTCPBridge
reactimateControl
bridge -- Communication channels
defaultPreferences -- Simulation preferences
([] :: [Command PosLowerThan]) -- Initial command queue
initGraphs
(\_ -> do
dtSecs <- yampaSDLTimeSense timeRef
return (dtSecs, Nothing))
(\_ e -> display e >> return False)
bouncingBall
display :: Double -> IO()
display y = do
-- Obtain surface
screen <- getVideoSurface
-- Paint screen green
let format = surfaceGetPixelFormat screen
green <- mapRGB format 0xAB 0xA9 0xBF
fillRect screen Nothing green
-- Paint small red square, at an angle 'angle' with respect to the center
red <- mapRGB format 0x34 0x11 0x3F
let radius = 20
let x = (width - radius) `div` 2
filledCircle screen x (height - round y) radius (Pixel 0xFF3411FF)
putStrLn (show (x, y, radius))
-- Double buffering
SDL.flip screen
bouncingBall :: SF () Double
bouncingBall = bouncingBall' (height / 2) 0 >>> arr fst
bouncingBall' :: Double -> Double -> SF () (Double, Double)
bouncingBall' p0 v0 = switch (fallingBall p0 v0 >>> (arr id &&& hitFloor)) (\(p,v) -> bouncingBall' p (-v))
fallingBall p0 v0 = proc () -> do
v <- (v0+) ^<< integral -< -9.8
p <- (p0+) ^<< integral -< v
returnA -< (p, v)
hitFloor =
arr (\(p,v) -> if p < 0 && v < 0 then Event (p,v) else Yampa.NoEvent)
initGraphs :: IO ()
initGraphs = do
-- Initialise SDL
SDL.init [InitVideo]
-- Create window
screen <- setVideoMode width height 16 [SWSurface]
setCaption "Test" ""
-- | 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 / 1000
return dtSecs
newtype PosLowerThan = PosLowerThan { limit :: Double }
deriving (Read, Show)
instance Pred PosLowerThan () GameOutput where
evalPred p dt i ey = limit p < ey
-- * Interactive reactimation
type GameOutput = Double -- b (output type of the SF)
myPred dt a ((ey,_),_) = ey < 450