Skip to content


Featured Posts

Why I switched from component-based game engine architecture to functional reactive programming

Components have become pretty popular these days and I'd like to share some issues we had with them in our game projects. I was experimenting with component-based game engine architectures for 2 years and eventually stumbled upon functional reactive programming (FRP) to solve some of the issues of game-object components. ...

Read More

Dataflow diagram of Yampa reactimate

download diagram (.svg), fonts (cmr10.ttf, cmtt10.ttf) For me as a Haskell beginner the biggest problem in understanding Yampa reactimate was how the objects are actually passed around and transformed as all the signatures are very, very... very generic. This diagram shows an example scenario staring Pacman (the player), a cherry (enemy ...

Read More

Aeon Racer mobile game

Today our little indie game start-up called Modern Alchemists released the first "bigger" game Aeon Racer for iPhone and Android! Check it out at http://aeon-racer.modern-alchemists.com (I declare an interest) I really do like the game mostly because of the controls. You really have to have fast reflexes to dodge the gates and I ...

Read More

FRP - Robotroannah Trailer

Robotroannah is a clone of the Robotron 2048 computer game. It uses functional reactive programming (FRP) with Haskell/Yampa and the hsSDL subsystem. FRP allows the functionality of a game to be connected in an incredible flexible and reusable way, resulting in about 250 lines of game specific code. Credits: FRP: ...

Read More

Slides about FRP and Yampa

Here is a presentation I held at the Johannes Kepler University (Linz, Austria on 2012-04-26) in Methods and Applications of Functional Programming: SlideShare (mirror 1) (mirror 2).


Connecting Yampa with LambdaCube-Engine

LambdaCube TileRacer Jochen Leopold

Abstract

In this post I present a minimal LambdaCube-Engine program which connects a 3D rendering engine to Yampa FRP. The code is an adaption of the lambdacube-basic.hs example delivered with lambdacube-examples. Some changes to Yampa were necessary to allow MonadIO transformations in order to connect with LambdaCube. The goal is to get quickstarted with Yampa and LambdaCube, so the code was intentionally kept simple. Full source code is available at bottom of post.

LambdaCube Examples

First we’re going to setup LamdaCube, run the lambdacube-basic example and see how it does work. Note that the latest version (0.2.4) of LamdaCube is available at GoogleCode (instead of Hackage (0.2.3)).

# cabal unpack lambdacube-engine # old version
svn checkout http://lambdacube.googlecode.com/svn/trunk/ lambdacube # new version
cd lambdacube/lambdacube-examples
dist/build/lambdacube-basic/lambdacube-basic
# ls lambdacube-examples.cabal
# ls src/lambdacube-basic.hs
# ls media/

It should show 1 frame of a bluesky scene. However it stops immediately because of an issue in Elerea FRP with the following message (bug report): thread blocked indefinitely in an MVar operation

This is unfortunate, however we’re going to integrate Yampa anyway. The important parts of the example are outlined here:

lambdacube-basic.hs (outlined)

import FRP.Elerea.Param
...

main = do
    openWindow
    ...
    runLCM renderSystem [Stb.loadImage] $ do
    ...
    addScene [ node "Root" "Obj" ...]
    ...
    addRenderWindow "MainWindow" 640 480 ...
    ...
    sc <- liftIO $ start $ scene ...        
    driveNetwork sc (readInput ...)

scene :: RenderSystem r vb ib q t p lp
      => ...
      -> SignalGen FloatType (Signal (LCM (World r vb ib q t p lp) e ()))
scene = do
        ...
        return $ drawGLScene <$> ...

drawGLScene :: RenderSystem r vb ib q t2 p lp
            => ...
            -> FloatType
            -> LCM   (World r vb ib q t2 p lp) e ()
drawGLScene ... time = do
    updateTransforms $ ...
    updateTargetSize "MainWindow" w h
    renderWorld (realToFrac time) "MainWindow"

What happens here is that a LCM world (LambdaCubeMonad) is created and several changes are made by “shoving” through the World via runLCM. Finally Elerea’s driveNetwork starts an infinite loop to make repeated renderWorld calls within the LCM context. So all we have to do is replace Elerea’s driveNetwork with Yampa’s reactimate and “shove” the LCM into reactimate. Unfortunately the types don’t match: (IO vs LCM). Also note how an external renderWorld is called within an LCM context. What’s going on? Let’s look up the definition! Because there are no public docs available we’ll generate them ourselves:

cd lambdacube/lambdacube-engine
cabal haddock
firefox dist/doc/html/lambdacube-engine/index.html
data LCM w e a

Instances
Monad (LCM w e)
Functor (LCM w e)
Applicative (LCM w e)
MonadIO (LCM w e)

What’s interesting here is that LCM instances MonadIO and provides a free type variable a. Thus LCM has an IO context and can be extended with other Monad contexts and types. All we have to do therefore is to make Yampa’s reactimate less strict and do some Monad lifting.

cabal install transformers

cabal unpack Yampa
cd Yampa-0.9.3/src/FRP

Yampa.hs

reactimate :: IO a
           -> (Bool -> IO (DTime, Maybe a))
           -> (Bool -> b -> IO Bool)
           -> SF a b
           -> IO ()

Change to:

import Control.Monad.IO.Class (MonadIO)
...

reactimate :: MonadIO m
           => m a
           -> (Bool -> m (DTime, Maybe a))
           -> (Bool -> b -> m Bool)
           -> SF a b
           -> m ()

Now we can call reactimate within runLCM and use Yampa as usual. Copy the lambdacube-basic.hs file and extend lambdacube-examples.cabal with the new executable.

YampaCube.hs (outlined)

type ObjInput  = (Int, Int)      -- mouse-position
type ObjOutput = (String, Proj4) -- object name, transformation

main :: IO ()
main = do
    mediaPath <- getDataFileName "media"
    renderSystem <- mkGLRenderSystem
    runLCM renderSystem [Stb.loadImage] (reactimate (initput title mediaPath) input output (process objs))
    closeWindow

initput :: RenderSystem r vb ib q t p lp
      => Bool
      -> LCM     (World r vb ib q t p lp) e (DTime, Maybe (Bool, ObjInput))
initput _ = do
    ...
    liftIO $ openWindow ...
    ...
    addScene [ node "Root" "Obj" ...]
    ...

output :: RenderSystem r vb ib q t p lp
       => Bool -> [ObjOutput]
       -> LCM   (World r vb ib q t p lp) e Bool

cam :: SF ObjInput ObjOutput
cam = proc _ -> do
    t <- localTime -< ()
    returnA -< ("Cam", translation (Vec3 0 0 (realToFrac t)))
cd lambdacube/lambdacube-examples
cabal configure
cabal build
dist/build/YampaCube/YampaCube

Download full source code: YampaCube.hs

Viola! What you should see is a small box with the bluesky texture and the camera slowly moving away from it.

Tagged with , , , .


My thesis has been released (german)

Game-Engine-Architektur mit funktional-reaktiver Programmierung in Haskell/Yampa

To be honest with you Haskell FRP cracks, you probably won’t find anything radical new and enlightening in it. It’s just Yampa applied on a more broad and abstract context to game development with some humble explanations of complex concepts.

Kurzfassung

Die Entwicklung von Computerspielen ist mit hohen Kosten verbunden, weshalb in der Softwareentwicklung wiederverwendbare und erweiterbare Funktionalität angestrebt wird. Ein aktueller Trend in der Computerspielentwicklung ist der Einsatz von Rapid Application Development und Prototyping-Software, wobei die schnelle Entwicklung spielbarer Prototypen und neuer Funktionalität in den Vordergrund gestellt wird. Dabei ist vor allem die dynamische Veränderung der Funktionalität zur Laufzeit wichtig, ohne dabei die Programmierumgebung gegenüber allgemeinen Programmiersprachen einzuschränken. Mit den bisher verwendeten objektorientierten Programmiersprachen und den komponentenbasierten Game-Engine-Architekturen konnten aber kaum Wiederverwendbarkeit, Erweiterbarkeit oder dynamische Funktionalität erreicht werden und schränkten die Programmierung durch die verwendeten Techniken zusätzlich stark ein.

In dieser Arbeit wird eine allgemeine Game-Engine-Architektur und verschiedene Basisfunktionalitäten von Computerspielen mittels funktional-reaktiver Programmierung in Haskell/Yampa behandelt. Durch die rein funktionale Programmierung kann die Funktionalität in vollständig unabhängige und wiederverwendbare Funktionen ausgelagert werden, während durch die reaktive Programmierung der Zeitverlauf völlig abstrahiert wird und die Funktionalität intuitiv aus reaktiven Elementen verknüpft werden kann. Weiters ermöglicht Yampa die Modellierung mit konzeptionell kontinuierlicher Zeit. Eine Game-Engine lässt sich dadurch insgesamt besser in deren elementare Bereiche aufteilen, wodurch sich der Datenfluss am Eingabe-Verarbeitung-Ausgabe-Modell veranschaulichen lässt und die grundlegende Funktionalität einer Game-Engine definiert werden kann. Abschließend werden die grundsätzlichen Grenzen von komponentenbasierten Game-Engine-Architekturen und dynamischer Funktionalität behandelt.

Abstract

Development of computer games comes at a high cost, thus reusable and extensible functionality is very essential in software development. A recent trend in computer game development is establishing Rapid Application Development and use of prototyping software, emphasizing fast development of playable prototypes and new functionality. Especially dynamic modification of functionality during runtime without limiting the programming environment compared to general purpose programming languages is important. Reusability, extensibility and dynamic functionality could hardly be achieved with object-oriented programming and component-based game engine architectures and the techniques used actually constrained programming.

In this thesis, general game engine architecture and various basic features of computer games are examined using functional-reactive programming in Haskell/Yampa. Due to pure functional programming, functionality can be encapsulated into completely independent and reusable functions, while reactive programming abstracts the flow of time and functionality can be composed intuitively via reactive elements. Furthermore, continuous time semantics are possible with Yampa. Overall, a game engine can be more clearly defined and divided into its basic features, thus allowing the data flow to be comprehensibly illustrated on the input-processing-output model. Finally, the principle limits of component-based game engine architectures and dynamic functionality are discussed.

Tagged with , , , , .


Yampa Haskell-Wiki update

I filled up the Yampa article on the Haskell wiki with all sources I knew and contributed all my diagrams (even some new ones, which I didn’t use on my blog yet). Hopefully this helps more people to get started functional reactive programming and keeps the good information on one central place.

Tagged with .


Update on Haskell and games

A news digest about Haskell and games

Update1: Animas

Tagged with , , , , .


A Survey of Functional Reactive Programming

A Survey of Functional Reactive Programming (pdf)
Original blog post

Interesting paper I wish existed when I wrote my thesis back then. Good overview of the different implementations which helps to understand the characteristics and problems of each library. Though I think it’s problematic to draw any conclusions about implementations without actually implementing anything with them. And he forgot to mention “Frag”, which is a quite sophisticated usage of an old version of Yampa. Nevertheless, a good read especially for beginners.

Tagged with .


Quickstarting Hipmunk


Hipmunk tutorial video

Abstract

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) 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.

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

Tagged with , .


Connecting Haskell FRP to the Unity3D game framework – part 1

Abstract

This post describes how to connect Haskell to Unity3D by compiling a Haskell shared library to a Win32 DLL and dynamically loading the DLL in a scripted Unity3D object via DLLImport. The DLL also uses an additional module (Yampa), thus FRP can be used within a sophisticated game framework (with the exception that this concept doesn’t connecte to the Unity3D core yet, which would allow stateful arrows within the game logic… which renders it rather useless right now :/).

Unity3D was chosen because it provides a complete game creation workflow and a demo version is available for free. In contrast, there are no full game creation frameworks available for Haskell right now (to my knowledge, but my status is based on ). DLLs were chosen over .NET libraries because to my knowledge it is not (yet) possible in Haskell to compile to a .NET library (and I think it was one of the reasons why F# was born). .NET libraries would of course allow for an easier integration in Unity3D. Unity plugins are only available in the pro version… which is a pity.

My personal goal was to connect functional temporal programming (functional reactive programming) to a sophisticated game framework to allow the creation of great games with FRP game logic. Besides, it was a great exercise for foreign function interfaces (FFI) and a test on how well Haskell can be integrated into existing applications.

Instructions

What actually happens when a Haskell program is packed into a shared library and called from an external program?
The actual DLL is built from C code, which exports the Haskell functions and also starts up a Haskell runtime, which delegates the external function calls to Haskell. All functions are called within an unsafe environment, like main :: IO () (… this shouldn’t necessarily be the case I think – FFI to Miranda?)

  1. Install at least GHC 7, because Windows DLLs don’t work with GHC 6 (see: GHC 7 change-log, section 1.5.4. DLLs: “Shared libraries are once again supported on Windows.”).
  2. Download and install Unity3D.
  3. Download DllTest.hs (Haskell code for game logic) and adopt to your needs.
    • As these function get evaluated within a unsafe environment, they are all IO Monads.
    • In Windows you have to use ccall (citation needed)
  4. Download DllTest.cs (Unity3D script file) and adopt to your needs.
    • Make sure to start and stop the Haskell runtime correctly. Nothing special really, just tag the external functions with [DllImport] and call.
  5. Visit GHC manual and search for // StartEnd.c and save the code to StartEnd.c.
    • This is the actual C program which is converted to a Windows DLL. It also starts up a Haskell runtime and allows the external program to call functions.
  6. Install all dependent modules with shared library option enabled (f.e. yampa) $ cabal install --reinstall --enable-shared yampa.
  7. Copy shared libraries of all used modules to your Haskell project directory C:\Program Files (x86)\Haskell Platform\2011.2.0.0\lib\yampa...\libHSYampa-0.9.2.3-ghc7.0.2.dll.a (…there may be a better solution for this)
  8. Copy the file C:\Program Files (x86)\Internet Explorer\IEShims.dll to your Haskell project directory (… forgot why)
  9. Compile step 1 $ ghc -dynamic -fPIC -c DllTest.hs
    • This is an intermediate step (see Shared libraries that export a C API) which produces the object file (.o) from C code (DllTest.o and DllTest_stub.o)
    • The -fPIC flag is required for all code that will end up in a shared library.
  10. Compile step 2 $ ghc -dynamic -shared DllTest.o DllTest_stub.o StartEnd.o libHSYampa-0.9.2.3-ghc7.0.2.dll.a -o libHsDllTest.dll
    • The object files, the runtime starter and the archive file for the additional module are compiled together into the final DLL.
  11. Use the DependencyWalker tool of the Visual Studio IDE to find errors in the DLL (it may be included in Visual Studio Express which is available for free).
  12. Create a Unity3D project and add an object using the DllTest.cs as a script file (this is out-of-scope of this article).

Notes on Haskell DLLs

Notes on Unity3D

  • When the DLL file is recompiled, Unity3D has to be restartet in order to reload the DLL.
  • If Unity3D doesn’t find the DLL file, make sure the correct DLL file (in the directory where $ ghc is executed) is located in your Unity3D project where the .exe file is located which gets compiled by Unity3D.
  • Unity3D log files are located in: C:\Users\myuser\AppData\Local\Unity.
  • Unity3D crash reports are located in: C:\Users\gerold\AppData\Local\Temp\crash_....
  • stdcall instead of ccall on Windows, this appears to be invalid for Unity3D (also see GHC manual on Win32 DLLs.
  • Unity3D uses the following script languages: C#, JavaScript, Boo.

Description

The actual concept is pretty straight forward. Simply write all Haskell functions and make the function interfacing to the external program an IO monad, which gets called by a potentially inpure program. The program and all depending modules are compiled into one big DLL. This DLL gets imported by the external program (Unity3D) and makes the functions visible. Before an Haskell function can be called, a complete Haskell runtime environment has to be started. In the following example, when an object is created, it starts up a Haskell runtime, runs an embedded arrow and shuts the Haskell runtime down again. This is of course rather useless right now, but it shows an arrow running in Unity3D.

DllTest.hs (short)

{-# LANGUAGE ForeignFunctionInterface, Arrows #-}

module Adder (
embeddedSF,
...
) where

import FRP.Yampa

embeddedSF :: Double -> Double -> Double -> IO Double
embeddedSF v0 v1 v2 = return . last $ embed integral (v0, [(1.0, Just v1), (1.0, Just v2)])

foreign export ccall embeddedSF :: Double -> Double -> Double -> IO Double

DllTest.cs (short)

class DLLTest : MonoBehaviour {
[DllImport ("libHSDllTest")]
private static extern void HsStart();
[DllImport ("libHSDLLTest")]
private static extern void HsEnd();
[DllImport ("libHSDLLTest")]
private static extern double embeddedSF(double v0, double v1, double v2);

void Awake () {
HsStart();
print ("embeddedSF: " + embeddedSF(12.0, 23.0, 45.0));
HsEnd();
}

DllTest.cs (short)

class DLLTest : MonoBehaviour {
[DllImport ("libHSDllTest")]
private static extern void HsStart();
[DllImport ("libHSDLLTest")]
private static extern void HsEnd();
[DllImport ("libHSDLLTest")]
private static extern double embeddedSF(double v0, double v1, double v2);

void Awake () {
HsStart();
print ("embeddedSF: " + embeddedSF(12.0, 23.0, 45.0));
HsEnd();
}

Resources

Haskell DLLs

Unity3D

Open questions

I don’t know how to integrate stateful arrows into the game logic yet. Probably the Haskell runtime within the DLL has to be started on some OnGameStart-event. Each object has to run its own independent arrow code and the update ticks propagated to something like the reactimate procedure.

(This post took ~4h to write, excluding development and writing the protocol, +1h update)

Tagged with , , , .


Cartesian Closed Comic

from Cartesion Closed Comic

lazy Schrodinger cat
Hahaha! :D
Sorry for the nerdy post.

lazy IO universe

Something similar bothers me since I understand Haskell a little more.

Tagged with .


Aeon Racer mobile game

Today our little indie game start-up called Modern Alchemists released the first “bigger” game Aeon Racer for iPhone and Android!

Check it out at http://aeon-racer.modern-alchemists.com

(I declare an interest)
I really do like the game mostly because of the controls. You really have to have fast reflexes to dodge the gates and I think particularly pro gamers will like it. We also released an free online version to try-before-buy, but the real fun unfolds using rotation sensors with a mobile device. Have fun and please leave a comment and rate us! :)

Tagged with .