Monday, September 24, 2007

Octane Mech, OpenGL Haskell based mech game; early code and some haskell notes


I am in the initial design and some development of OctaneMech; as the title implies is a OpenGL Haskell based Mech (bot, tank mobile) game.

An early goal is to recreate/port glAnts (mech game) to haskell
http://glants.sourceforge.net/

On Haskell

Haskell is a pure functional programming language where your primary view of your software is through the use of functions. In java or other objected oriented/imperative languages, you are looking at the lowest level components; in Haskell, you are able to concentrate on the operation a particular function is used for without focusing on the low-level details (step-by-step sequences) of the function.

I won't now or probably in the future detail the power you are given with Haskell and I leave that up to you the reader. I will focus on how I am using Haskell to build my project. And this first entry will contain some simple Haskell snippets.

Main

Like other applications, a Haskell application begins with entry point definition main function. For example, the following snippet below is all that is included in my Main module (included in a text file called OctaneMech.hs)

module Main where

import MechGLScreen
main = do
putStrLn "running OctaneMech"
mechLaunchGLWindow

It almost resembles a Hello World application. We import the needed library "MechGLScreen" and then write our main definition. putStrLn was used to print the startup message. mechLaunchGLWindow, is going to get a little bit more complicated. It includes the OpenGL initializations and sets the display callback.

Launch OpenGL

This function also may resemble more the sequential, call by call nature of an imperative program. If you are used to OpenGL development, most of the calls are window and GL initialization. It may get a little bit more interesting with the "SimplePlayer" data type which is composed of a x and y position.

mechLaunchGLWindow
= do
getArgsAndInitialize
initialDisplayMode $= [DoubleBuffered]
initialWindowSize $= Size mechScreenWidth mechScreenHeight
createWindow mechWindowTitle

curMech <- newIORef (SimplePlayer {
shape = MechBoxShape,
posX = 0,
posY = terrainYSize-ssize,
angle = 0})
-- Get the current and rotation matrices
curMatrix <- get ((matrix $ Just $ Modelview 0)::StateVar(GLmatrix GLdouble))
rotationMatrix <- newIORef curMatrix
-- Keep track of camera movement
cameraRotPosition <- newIORef (0::GLint, 0)

-- Set the OpenGL callbacks
displayCallback $= displayGameLoop curMech rotationMatrix

-- Set the keyboard callback for handling actions
keyboardMouseCallback $= Just (mechKeyboardHandler curMech)

idleCallback $= Just idle
mainLoop

This particular function initializes the GL window and other game initializations. Now, open the MechDisplay.hs source. This function contains operations for swapping the GL double buffer and rendering the plain (Quad) object and player character (a simple cube).

displayGameLoop mechObjRef rotationMatrix = do
clear [ColorBuffer]
curMech <- get mechObjRef
prevMatrix <- get rotationMatrix
loadIdentity
multMatrix prevMatrix
curMatrix <- get ((matrix $ Just $ Modelview 0)::StateVar(GLmatrix GLdouble))
loadIdentity
scale 0.06 0.06 (0.06::GLfloat)
multMatrix curMatrix
-- Render the terrain, including the flat plain
renderTerrain
-- Render the Mechs
renderBasicMech curMech
-- OpenGL, swap buffers
swapBuffers

And I know it is short entry but I will actually continue in my next couple of posts on this topic. See all of the source code for this simple example below. Once you have it compiled, you should only see a 640 by 480 window open up and then you are able to use the keyboard (arrow keys) to move the "box" character around.

Source for Example

Download Haskell Example

Follow the Project at Googlecode:

http://code.google.com/p/octanemech/















Note: google code is horrible about the code formatting, so you will have to browse the included source to view the correct indentation

No comments: