Quickstarting Hipmunk

This blog post was originally written back in 2011-04-23

Abstract

Youtube - Hipmunk tutorial video

This post describes a minimal Hipmunk program, a Haskell binding to the Chipmunk 2D physics engine, featuring a simple falling circle with circle collision shape. The goal was to exemplify how a Hipmunk program is structured corresponding to a FRP game engine model (see The Yampa Arcade (archived)) and testing a sophisticated 2D physics engine (for simplicity) with Haskell. A physics engine could actually be completely pure, investigations retrieved Hpysics, a pure functional physics engine. Didn’t use it, looks very basic, yet complete, but it’s an abandoned project.

Youtube - Hpysics simple demo

Description

Most rigid body physics engine define the following objects:

  • Space: a physical simulation space independent from other spaces, describes gravity. When a body is added, the object becomes dynamic. When the shape is added too, collisions are also handled.

  • Body: a point which describes the position, using mass, moment of inertia (rotation), velocity, force, torque etc.

  • Shape: a geometrical figure which describes collision shapes and optionally has an offset to the body (f.e. when using multiple shapes)

  • Constraints: describe different restrictions on the movement of Bodies, like Pins, Springs, Ropes…

The scene definition thus is pretty straight forward: setup scene, run simulation, handle collisions, loop. What is unfortunate though is that – like all FFI bindings – the binding to the external Chipmunk engine is fundamentally unsafe, so there are lots of IO Monads to do basic stuff. Using Hipmunk in a FRP environment like Yampa would require lots of “task-” (or “message-”) definitions and communication from the logic all the way to the physics engine, only to apply forces. Note the many unnecessary IO and State Monads. Here is a small code snipped which does 3 simulation steps:

import Control.Monad
import Data.IORef
import Data.StateVar -- defines $=
import qualified Physics.Hipmunk as H

main :: IO ()
main = do
    H.initChipmunk                         -- initChipmunk :: IO ()

    space <- H.newSpace                    -- newSpace :: IO Space
    H.gravity space $= H.Vector 0 (-10)    -- gravity  :: Space -> StateVar Gravity

    body <- H.newBody mass momentOfInertia -- newBody  :: Mass -> Moment -> IO Body
    -- (+:) is a convenient function for vector construction defined in Playground.hs
    -- compare with H.Vector above
    H.position body $= 0 +: 0              -- position :: Body -> StateVar Position

    -- class Entity a
    -- instances: Shape, Body, StaticShape, (Constraint a)
    H.spaceAdd space body                  -- spaceAdd :: Space -> a -> IO ()

    -- newShape :: Body -> ShapeType -> Position -> IO Shape
    shape <- H.newShape body (H.Circle 5) offset

    -- step :: Space -> Time -> IO ()
    H.step space elapsedSeconds -- IO () => y = 0
    H.step space elapsedSeconds -- IO () => y = -10
    H.step space elapsedSeconds -- IO () => y = -30

    pos <- get . H.position $ body
    putStrLn . show $ pos

  where
    mass = 1.0
    momentOfInertia = H.infinity
    offset = H.Vector 0 0
    elapsedSeconds = 1.0

-- | Constructs a Vector.
(+:) :: H.CpFloat -> H.CpFloat -> H.Vector
(+:) = H.Vector
infix 4 +:

References