Skip to content
September 5, 2011 / cdsmith

Games: Now Available in Gloss-Web

At long last, I can announce the game interface in gloss-web.  This is still a good ways off in my class, but those of you who know what you’re doing can play around with it anyway.  As always, you can visit

http://dac4.designacourse.com:8000

If you’ve used the site before and don’t see a game button, you may need to hit the refresh button.

How they work:

Games are similar to simulations, except that the time-step function has one fewer parameter, and there’s an additional event handling function.  So you’ll need to write the following:

initial :: StdGen -> a

Just as with simulations, you can pick any data type you like (and probably write your own) to represent the state of the world.  You then define initial to be a function that gets a random number generator, and returns the starting state.  If you need random numbers, you can store the generator in your state type.  The type variable a needs to be the same as a in all the definitions that follow.

event :: Event -> a -> a

Here’s how you respond to events: write a function with the event and the previous state of the world, that returns a new state of the world as its result.  That means anything you want to remember about the events that have happened should be part of your world type.

step :: Float -> a -> a

Here’s how you respond to the passage of time.  Much like the step function of the simulation interface, the time parameter is the amount of time that’s elapsed since the last step.  Unlike simulations, there is now ViewPort passed in.  That’s because in the OpenGL implementation, simulations automatically provided controls to zoom and such… but games don’t.  So you just get the elapsed time.  (Of course, gloss-web doesn’t provide those automatic transformations anyway.)

draw :: a -> Picture

Finally, of course you need to draw the world.  This is where you say what it looks like.

An Example

The default program is a fairly simple one that draws a ball where ever you place the mouse; not much of a game, really!  Never fear, here’s something a little more involved… and actually pretty fun!  My best score so far is 31.  Can you do better?

import Graphics.Gloss
import Graphics.Gloss.Interface.Game

data World = World {
    player :: Point,
    target :: Point,
    goal   :: Point,
    robot  :: Point,
    speed  :: Float,
    score  :: Integer
    }

initial _ = World (0,0) (0,0) (200,200) (-200,-200) 40 0

event (EventMotion (x,y)) world = world { target = (x,y) }
event _                   world = world

distance (x0, y0) (x1, y1) = sqrt ((x1 - x0)^2 + (y1 - y0)^2)

moveToward (x0,y0) (x1,y1) dist = (x0 + dx, y0 + dy)
    where totalDist             = distance (x0,y0) (x1,y1)
          dx | dist < totalDist = (x1 - x0) * dist / totalDist
             | otherwise        = (x1 - x0)
          dy | dist < totalDist = (y1 - y0) * dist / totalDist
             | otherwise        = (y1 - y0)

collisions world | distance (player world) (goal  world) < 40 = foundGoal
                 | distance (player world) (robot world) < 40 = initial
                 | otherwise                                  = world
  where foundGoal = let (x,y) = player world
                    in  world { goal = (-x, -y), score = score world + 1 }

step time world = collisions newWorld
  where
    newWorld = world {
        player = moveToward (player world) (target world) (time * 60),
        robot  = moveToward (robot world)  (player world) (time * speed world),
        speed  = speed world + (0.1 * time)
        }

draw world = pictures [
    color blue  (figure (player world)),
    color red   (figure (robot  world)),
    color green (figure (goal   world)),
    translate (-225) (-225) (scale 0.2 0.2 (text (show (score world))))
    ]

figure (x,y) = translate x y (circleSolid 20)

Have fun!

6 Comments

Leave a Comment
  1. robkinyon / Sep 5 2011 7:55 pm

    The site seems to be down. :(

    • cdsmith / Sep 5 2011 8:00 pm

      Yikes, back up! Not sure what happened there.

  2. Simon Meier / Sep 6 2011 2:24 am

    Hi Chris,

    great work you’re doing here! The game is fun :D

    It would be even more cool, if one could choose to render the image on the client computer. I would expect that providing a remote renderer backend for gloss that is based on WebGL could be implemented with reasonable effort. One can always fallback to your existing backend for browsers that are not that up-to-date.

    If I’d have some more spare time, I’d actually love to tackle this as a learn-me-a-WebGL project. I’d just love having these super snappy animations powered by Haskell :-)

    • cdsmith / Sep 6 2011 1:33 pm

      So we actually are rendering on the client computer, but using the “2d” rendering context. The code runs on the server, though, as I haven’t yet figured out how to compile Haskell to JavaScript. The server then embeds (in picture mode) or streams with server-sent events (in all other modes) a custom base64-encoded binary vector-graphics-ish description of the image to the client.

      It would no doubt be possible to swap out the rendering system from 2d to WebGL… and if you’d like to do that, maybe there are benefits to using WebGL rendering on browsers that support it. At least it would fix the circle and line rendering bug on Opera that I just found today, at least for very recent Windows development builds of Opera that support WebGL, and maybe it would be less likely to run into platform-specific quirks in the first place.

      • Simon Meier / Sep 6 2011 2:17 pm

        Ah I see. I assumed the not-so-fluent framerate in the game was due to the whole image being sent from the server. Having now inspected the JavaScript behind the page, I can see the vector graphics that you send.

        I don’t think using WebGL will give you less platform specific quirks. It seems to be an even newer standard than the 2D canvas. It might be worth it in case you’re thinking about going into the third dimension ;-)

        Thanks for your explanation. I’m looking forward to seeing the further progress of your class.

      • cdsmith / Sep 6 2011 6:29 pm

        Ah… no, the not-so-fluent frame rate is actually mostly because I intentionally throttle the server to 10 frames per second, to avoid excessive bandwidth usage if you leave it running for a long time. You can grab the code from github and change the fps throttle to something else, and it will run faster on a really good network connection.

        Implementing some kind of buffering is also on my todo list, but I imagine I won’t apply it to the game interface by default; just to animations and simulations.

Leave a reply to Simon Meier Cancel reply