packages feed

yampa-glut-0.1.1: example.lhs

Useful syntax for working with @Arrow@ and associated combinators

> {-# LANGUAGE Arrows #-}
> import Control.Arrow

We know that our @Action@ objects have @Monoid@ property. Use that fact by
combining them through @mconcat@

> import Data.Monoid

Nice set of operators for Vectors manipulation

> import Data.VectorSpace
> import Data.VectorSpace.OpenGL

GLUT supplies us with a lot of already predefined objects (among them is teapot and sphere).

> import Graphics.UI.GLUT

Here we get our @Reaction@ processing and @simpleMousePosition@ signal
function.

> import FRP.Yampa.GLUT.Adapter

> import FRP.Yampa (SF, integral, delay, initially, edge, accumHoldBy)
> import FRP.Yampa.Event

Our small Simple game

> main = do
>     simpleInit "Simple"
>     cullFace $= Just Back
>     frontFace $= CW
>     shadeModel $= Smooth
>
>     blend $= Enabled
>     blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
>
>     lighting $= Enabled
>     ambient (Light 0) $= Color4 0.1 0.1 0.1 (1::GLfloat)
>     diffuse (Light 0) $= Color4 0.9 0.9 0.9 (1::GLfloat)
>     position (Light 0) $= Vertex4 0.5 0.5 (-10) 0
>     light (Light 0) $= Enabled
>     colorMaterial $= Just (Front, AmbientAndDiffuse)
>
>     adapt leaveMainLoop simple

Description of events flow through our game

> simple :: Reaction
> simple = proc ev -> do
>     pos <- ball -< ev
>     disp <- redisplay -< ev
>     reshapedAction <- fmap (actionIO . reshape) ^<< reshaped -< ev
>     returnA -< mconcat [
>       reshapedAction,
>       disp `tag` actionIO (display pos)
>       ]

Display takes our in-game state and draws it

> display (x, y) = do
>     clear [ ColorBuffer, DepthBuffer ]
>
>     preservingMatrix $ do
>         translate (Vector3 (realToFrac x) (realToFrac y) (0 :: GLfloat))
>         color $ Color4 0.2 0.8 0 (0.5::GLfloat)
>         renderObject Solid (Sphere' 0.1 50 50)
>
>     swapBuffers

Our reshape callback is trying to keep aspect ratio.

> reshape sz@(Size w h) = do
>     let b = fromIntegral (w `min` h) * 2
>         w' = fromIntegral w / b
>         h' = fromIntegral h / b
>
>     viewport $= (Position 0 0, sz)
>
>     matrixMode $= Projection
>     loadIdentity
>     frustum (-w') w' (-h') h' 2 100
>
>     matrixMode $= Modelview 0
>     loadIdentity
>
>     translate (Vector3 0 0 (-4 :: GLfloat))

Internal state of in-game object represented by two @Float@'s. That's recursive
signal function that affected by user input.

> ball :: SF (Event UI) (Float, Float)
> ball = proc ev -> do
>         d <- moveDirection -< ev
>         (Vector2 tx ty) <- simpleMousePosition -< ev
>         rec
>             let mpos = (tx, ty)
>                 dpos = mpos ^-^ pos
>                 speed = normalized dpos ^* 0.5 ^* d
>             pos <- integral <<< delay 0.2 zeroV -< speed
>         returnA -< pos

Direction

> moveDirection :: SF (Event UI) Float
> moveDirection = mouseButtonPressed LeftButton >>> edge >>> accumHoldBy (const . negate) 1