Skip to content


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

    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

    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

1 2 3 4

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


multicore cabal install

There are lots of tutorials on how to do parallelism, concurrency and multicore (dualcore, quadcore etc.) compiling with Haskell. I had a hard time however finding anything on how to run the GHC compiler itself on multiple cores, in order to speed up cabal install (cabal configure or cabal build). Here’s how you do it:
cabal install --ghc-options="+RTS -N2 -RTS"

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 .


Profiling an interactive simulation in Haskell – part 1

Abstract

This post is a feasibility test for developing bigger computer games using functional reactive programming (a.k.a. functional temporal programming) with the Yampa library. I use GHC performance profiling on a small interactive computer game simulation which implements animation, rendering, collision detection, artificial intelligence and game object management on a very basic level (see Robotroannah video). The focus is however on Yampa specific code, i.e. animation, AI and object management logic. The game will be scaled up to several hundred objects with different behaviours where one frame has to be calculated on a “reasonable speed”. I don’t want to make it just run “smooth enough overall” because physics and rendering will be replaced in future anyway.

Instructions

  1. “You can’t optimize what you can’t measure”
  2. Define goals (60 fps, profile only module X etc.) and simplify to the necessary parts.
  3. Understand time profiling, heap profiling and cost centers.
  4. Create reproducable conditions in interactive programs.
  5. Compile with ghc --make myprog.hs -o myprog -prof -O2 -fforce-recomp
  6. Use -auto, -auto-all or -caf-all to automatically add additional “interesting” cost-centers. I prefer -auto as the other produce lots of spam.
  7. Use -fforce-recomp compiler flag when adding {-# SCC "COST_CENTER_NAME" #-}.
  8. Performance profile with ./myprog +RTS -p. Open myprog.prof.
  9. Heap profile with ./myprog +RTS -h; hp2ps myprog.hp. Open myprog.ps
  10. End all unnecessary processes to produce stable conditions and profile several times to get stable results.
  11. Always document conditions and code changes in profiling reports.
  12. Always profile with -O2 compiler options. Otherwise you may optimize the wrong program parts.

Lessons learned: Even if Haskell is still in heavy development and it’s okay to question the profiler, investigate it’s strange claims first and see if it resolves the bottlenecks. If it does: good :) . If not, question the tool.

Open questions

  • How can I define the filename of profiling output? (possibly with > shell operator)
  • How can I automatically numerate files?
  • How can I guarantee that certain code parts are always evaluated? (possibly with strictness)
  • How can I sort by constant and linear heap consumption in hp2ps?

GHC 7
In GHC 7 the -rtsopts compiler flag is used to activate runtime options. I found a bug in profiling however and had to switch back to GHC 6.12.1. Bug report: bug report “<<loop>> when compiling with -O option with ghc-6.10.0.20081019″

Protocol

Status quo

The original version of the computer game “Robotroannah” implements simple animation (animateLoop, animateLoopFrame), AI (knightObj), physics (observeTypeCollisions) and object management (createReq, deleteReqs). The rendering takes 3 render steps (legs, body, head) with a fixed-frame rate of 60Hz using SDL.delay to “sleep away” available frame time (1000/60 = 16.67ms). Spritesheet resources are loaded once but passed to each object every cycle(!) right now. Object management logic uses the dpSwitch from The Yampa Arcade.

Goal

  • First performance profiling
  • First heap profiling
  • Investigate heap consumption
  • Profile 100 mines in isolation (animation only)
  • Profile 100 knights in isolation (animation + AI)
  • Profile object management in isolation

Performance profiling 1

In performance monitoring we know that “you can’t optimize what you can’t measure” and that “we must not make any assumptions about performance bottlenecks”… and I have a good real world example for this: I implemented a resource manager to avoid passing the spritesheet resources to every object as I assumed it would take alot of memory which later turned out not to be a problem at all (which in turn I assume because of laziness).

First I implemented a frame counter which sufficed as a simple indicator for slow performance. The game was indeed slow and took 18ms to render a single frame with only 3 objects(!) (target is 16.67ms).

In order to create reproducable results I had to create some sort of “user-input recording” to replay the same simulation but I eventually just used “no input at all” for now and automatically killed the simulation after exactly 10 seconds. I also removed the “sleep away available frame time”. Thus the problem of “profiling an interactive program” turned into a problem of “profiling of rendering 6000 frames as-fast-as-possible” (60fps * 10sec = 6000).

To simplify the scene I removed the player object and increased the number of objects to 100 “mine objects”. I also replaced the object management dpSwitch with a parB to exclude performance impacts from object creation and deletion. This may produce an artificial situation however as Haskell may do some optimization (like caching) which will not happen when there are different objects.

    Mon Jan  3 19:53 2011 Time and Allocation Profiling Report  (Final)

       robotron +RTS -p -RTS

    total time  =        5.76 secs   (288 ticks @ 20 ms)
    total alloc = 501,932,352 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

outputSDL                      Venice.Subsystem.SDL  57.3   26.6
observeTypeCollisions          Venice.Process        12.2   11.0
animateLoop                    Venice.Process         7.6   16.3
animateLoopFrame               Venice.Process         7.3    8.3
mineObj                        Robotron.Objects       4.9   14.1
main                           Main                   3.5    4.0
core                           Main                   1.7    8.4
playerObj                      Robotron.Objects       1.4    1.2
elemsIL                        Venice.IdentityList    1.4    4.3
body                           Robotron.Types         1.0    0.3

Summary

  • 60% spent in rendering which is plausible. I can ignore rendering, but I added more cost-centers to further investigate just out of curiosity.
  • 15% spent in physics which is also plausible and I also can ignore.
  • 15% spent in animation which is strange I guess.
  • 500MB total allocation with 6000 frames! What the heck?

Heap profiling 1

(Nevermind the inconsistencies of the date and objects please! I just forget to keep the original reports but they look similar.)

As you can see there are some space leaks as the heap consumption grows lineary even though no objects are added. I tested animateLoop and animateLoopFrame in isolation which turned out to have constant consumption. These space leaks actually took me quite some time to track down. What I should have done actually is focus on the calling function – mineObj (or cometObj). I originally assumed that it only does some initialization and assignment which couldn’t have any impact on the performance. This however contradicted with the profiling report (5% spent in mineObj). I later indeed found the cause in mineObj: Every frame I do a conversion from spritesheet space to SDL rendering space, which actually could be done once-and-forall in the initialization step. The new heap profile looks far better.

The new performance profile still looks the same however :/

    Sun Jan  9 21:39 2011 Time and Allocation Profiling Report  (Final)

       robotron +RTS -p -RTS

    total time  =        6.92 secs   (346 ticks @ 20 ms)
    total alloc = 496,279,440 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

outputSDL                      Venice.Subsystem.SDL  64.7   30.8
animateLoop                    Venice.Process         8.4   18.9
observeTypeCollisions          Venice.Process         6.9    1.2
mineObj                        Robotron.Objects       6.4   15.6
animateLoopFrame               Venice.Process         5.8    9.5
main                           Main                   2.6    4.9
core                           Main                   2.0   10.1
body                           Robotron.Types         1.2    0.4
output                         Main                   0.3    1.1
elemsIL                        Venice.IdentityList    0.0    5.2

A mystery I will resolve another time…

References

Tagged with , , , .