FunSpIns - Drawing a Rectangle

18 Sep 2013 in software-development | haskell | fun-spin |

Functional space-invaders series

  1. A recap of Rob Ashton’s lessons - Das Intro
  2. Drawing a Rectangle
  3. Moving a Rectangle
  4. No attributes, No vectors, A tiny Workflow and more squares
  5. State, the World, the Loop
  6. The hero must move, the enemies must move smarter
  7. The hero shoots
  8. Collisions, the dead, and a (not so) grateful ending

Inspired by Rob Ashton’s series “Learn functional programming with me

It probably is a good idea to introduce to some basic syntax:

A Haskell function call:

letme "die" "twice"

Here, letme would be the function, whereas the remaining parts would be arguments passed to it.

A Haskell function definition:

letme:: String -> String -> String
letme x y = x ++ " " ++ y

In Haskell, Types are sooper-important. In this example we have specified the signature of the function explicitly. As a sidenote, we don’t have to do that, in this case Haskell would have inferred the following signature:

*Blog> :t letme
letme :: [Char] -> [Char] -> [Char]

*) btw, this is taken from the ghci the interactive way to talk with Haskell.

Huh, not as generic as we thought, how come? - Reason’s the ” “ in the function definition. Anyway, on to other stuff.

Assuming you got Haskell ready to talk to SDL (see previous post in the fun spins series), we need to think about how to draw a rectangle.

Drawing a rectangle certainly is IO, hence that kind of thing will have to happen in Haskell’s IO context. In that context it is a fairly OK thing to have an entry point - leering a bit at animal machine’s series, we can get us a nice lil’ entry point:

module Game where

  import Graphics.UI.SDL as SDL

  main :: IO ()
  main = do
   SDL.init [SDL.InitEverything]
   SDL.setVideoMode 640 480 32 []
   SDL.setCaption "Draw Rectangle"
   eventLoop
   SDL.quit
   print "done"
 where
   eventLoop = SDL.waitEventBlocking >>= checkEvent
   checkEvent (KeyUp _) = return ()
   checkEvent _ = eventLoop

Woa, OK - main is a thing that runs in an IO context and returns nothing ( hence the () ). »= has a type definition of

Monad m => m a -> (a -> m b) -> m b

Which reads along the lines of

Given some thing of type a running in a context and a function that accepts something of type a and returns some type b running in the same context, get me the result of said function, wrapped in that context we mentioned.

I doubt that this helps you, for now it doesn’t help me a lot, but I think it is pretty clear what effect the code has. We have ourselves a nice event loop which I am sure will come in handy later on.

So, what about that frikkin’ rectangle?

module Main where

  import Graphics.UI.SDL as FX

  main :: IO ()
  main = do
       FX.init [InitVideo]
       FX.setVideoMode 640 480 32 []
       canvas <- FX.getVideoSurface
       FX.fillRect canvas (Just (Rect 25 25 100 100)) (Pixel 0xFFFFFF)
       FX.flip canvas
       eventLoop
       FX.quit
   where
       eventLoop = FX.waitEventBlocking >>= checkEvent
       checkEvent (KeyUp _) = return ()
       checkEvent _         = eventLoop

Paints us a white rectangle at position 25,25 with a width and height of 100 pixels.

A word on running the program

You can either

  • start ghci and then type :load game, where your file is called game.hs, or
  • use the compiler like ghc -o game game.hs

Chronology

  |  
comments powered by Disqus