Ask YC: Game programming in Lisp - is it possible?
Dear HN,
I have been programming small games in Java for the past 3 years or so and would like to expand my horizons by learning functional programming.
Is it possible to make games using something like Lisp (or another functional language)? Would there be any benefits as opposed to OOP?
For instance: say I want to make a pacman game. In java, you just have a bunch of objects that keep their state and thus globally keep the state of the game. Then you check for collisions etc. But in Lisp, you don't have state - so would that be possible to make pacman purely functionally? If so, how? And would there be any benefits?
(
40 comments
| 37 points
| on HN
)
Good libraries, particularly multimedia ones, will be very important. Chicken Scheme has a great library collection (http://www.call-with-current-continuation.org/eggs/) and works well with C. (Chicken compiles Scheme to C.) Other people here strongly recommend PLT Scheme, though I haven't personally used it much.
For learning functional programming in Lisp, I'd recommend starting with The Little Schemer. After that, The Seasoned Schemer and/or SICP.
I would also consider Lua under those circumstances. Game programming is one of its strongest areas, and IMHO it is a very practical and well-designed language. (Lua and Scheme are, by far, my favorites.) You can also do FP in Lua, though it's not really emphasized, so Scheme is better suited to learning it.
http://www.haskell.org/haskellwiki/Frag
I think part of the issue is that writing a game in Haskell is a novel challenge (it's running head-on into the weak points of the language), so the people who succeed make a big deal out of it. I'm not saying they don't deserve credit, but if they had used more appropriate language(s), the game would be judged on its own merits, you know? Similarly, I find kkrieger (http://www.theprodukkt.com/kkrieger) quite impressive. Not because of great gameplay (I don't even like first-person shooters), but because they fit so much into 96kb.
Half the original post's question is about learning functional programming. That's one of the niches where Scheme trumps almost everything else, and I also think Scheme is worth learning in general.
There are also ABCL (Common Lisp) and SISC (Scheme) if you want something standard that still runs on the JVM.
Plusses:
-JVM at your disposal
-STM for concurrency (haven't used this much yet but what it offers is nice)
-built-in collection types like you'd see in perl, js, python, etc., which is a much nicer syntax over the more traditional lisp dialects for those of us who aren't hard core lisp programmers.
-nice emacs/slime integration - REPL for debugging, etc.
Minuses:
-The language is still being actively developed and while most of the core features are there, there are some things that I've found missing and some things that are still changing (have had trouble with the project/module/package heirarchy a bit, would like metadata on anonymous functions).
-Debugging can be tricky, stuff will come up from the JVM without an associated line number in the clojure code, though I've seen a patch for this online
-Complexity added by the plusses. The java interop has a lot of power but it takes some getting used to. I also came into this with no recent java experience so YMMV.
-No native OO syntax, and I didn't want to write a hybrid of java/clojure code. Still, it has structs, and the idea (I think) is to use closures as the "glue" rather than objects.
You came to HackerNews, where all the functional programming boosters hang out (myself included) and asked: can I use functional languages for X? What, were you expecting an unbiased answer? To HackerNews, functional programming can do X optimally, forall X.
All languages have tradeoffs, though it sometimes seems like we have yet to face up to the tradeoffs in functional programming. But in truth, functional programming kinda sucks for games, and the more functional it gets (that is, as it approaches Haskell), the more it sucks. Because game logic is all about the one thing that pure functional programming disdains with all its heart: global internal state and side effects. The purer you get the more you have to jump through hoops to manage this kind of stuff. So IMHO you're really asking: can I learn a functional programming language by coding something which functional programming is fairly hostile? And people here are responding: sure, you'll love it! It's perfect for you!
Also note that real game programming is also often about speed and soft real-time guarantees. Sure, games often have a high-level scripting language in which certain gameplay elements are written. Lua, for example, is one popular choice. Variations on Javascript are another. But if you're looking to write a game in a programming language, and need to eek out that extra bit of cycles to do something nifty, most of the languages here are bad bad choices. This is probably not something you care about since you're just looking to learn, which I applaud. But it does tell me that boosterism is in effect when people recommend Lua and Clojure and ABCL and SISC for game programming that they've not considered, and they don't bother to tell you that these languages are quite slow, for an environment (games) where speed really matters.
So if you're trying to learn a functional language by doing a game, I'd pick the least hostile functional language that has highly portable graphics and event support and which is decently fast. Ordinarily I'd say CommonLisp, but ABCL's not there yet. One language in this category is Kawa, a JVM scheme which can be optimized to run at a decent fraction of Java. PLT might be another choice: it's not super fast but has very strong and portable libraries.
Scheme is a good language for learning functional programming. (Haskell is as well, but I would argue that several techniques the poster is likely to learn from Haskell are difficult to use in non-lazy languages, and telling them apart requires experience they probably do not possess. Also, Haskell is very poorly suited to games, and (* dodges rocks* ) seems to me like a less practical language overall .)
Also: Lua is fast (certainly fast enough for prototyping), and has a clear migration path to C / C++ for libraries and the parts of the game that need the raw speed. Something on the JVM (including Java, of course) may better suit the author, since they are probably already familiar with many of the relevant libraries, but I don't have much experience there.
http://en.wikipedia.org/wiki/Abuse_(computer_game)
Any other examples?
Unfortunately they were purchased by Sony and had to stop using Lisp... I guess it's the same story as viaweb/yahoo store :-)
See : http://www.franz.com/success/customer_apps/animation_graphic... http://c2.com/cgi/wiki?LispInJakAndDaxter
Which is a little different from wanting to learn functional programming by writing a game. ;)
It's pretty obvious that since you can do this, a game like PacMan can also be done. I don't see any obstacle to writing 3D games. Common Lisp has been used for a huge range of kinds of application.
If you're looking for a languages with no side-effects in the same sense as in Haskell, the Clojure dialect of Lisp is well worth looking at.
I work only a few offices away from the Xbox developer support team, so I've heard a few war stories about game scripting. Artists and designers at one huuuuge studio (I won't mention their name) have been using Lisp for runtime tweaking of weapon, AI, and vehicle behavior (among other things) for well over a decade without even knowing that it is Lisp.
Naughty Dog used their own GOAL (Game Oriented Action Lisp) for Jak and Daxter, which you can read all about at http://www.gamasutra.com/features/20020710/white_02.htm
I think the bottom line is that you need to use raw C/C++ for the fast core graphics stuff, but once you stitch your engine together in a way that supports easy COMPOSITION, then you need a scripting language. Most studios with custom engines choose Lua or similar. Big engines like Unreal and Doom use their own. Some clever teams write their own Lisps.
It developed primarily for use as an embedded language, so the Lua authors have kept the core very small. It's easy to use it with C, and to extend the core with libraries written in C or Lua. Many things that other languages require in the core can just be loaded as libraries. This means that (much like Scheme) it makes for a clean foundation for interesting CS projects -- LPEG (http://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html) is a novel parsing/pattern matching system, there's a new library to add Erlang-style concurrency (http://concurrentlua.luaforge.net/), LuaJIT (http://luajit.org/) is a cutting edge JIT compiler, etc.
It's trivially portable to anywhere C is used, and is quite fast. It's also distributed under a BSD license, if your company wants to use their own fork internally (it's ~500k of source). You can also deliver executable files with byte-compiled Lua embedded in them.
Stylistically, it's probably closest to Python, but with more Scheme influence (tail-call optimization, coroutines, non-crippled "lambdas", etc.). It's idiomatic to make heavy use of tables, which are very similar to Python dictionaries.
The standard intro is _Programming in Lua_ (http://www.inf.puc-rio.br/~roberto/pil2/). The first version (covering Lua 5.0) of the book is free online, but there were some significant changes to the language with 5.1, particularly the module system.
It has some downsides as a Language (the community, while nice, is rather small, so sometimes documentation is sparse or scattered; it's generally assumed you're already using C or C++, so the standard libraries have gaps when using Lua on its own; the module system is still maturing (LuaRocks (http://luarocks.luaforge.net/rocks/) is an attempt to fix this); etc.), but picking any particular language always involves trade-offs. I've been quite pleased with it.
(Also, MIT license, not BSD.)
Check out their website for the demo video and screenshots of the game:
http://www.gamerizon.com/
Btw, they are now hiring.
Ypsilon has been developed as a fundamental technology for LittleWing Pinball Construction System.
More info:
http://www.littlewingpinball.com/contents/en/ypsilon.html
There's a small thinking shift between writing a game in an imperative style and writing it in a functional style. In particular, it's smaller, I think, for games than for other kinds of applications.
In a typical game, you have a global state - a series of objects describing the properties of the game world at a certain time. You continuously update these objects, based on what input you receive from the user, and then present those changes to him, by way of video and audio rendering.
In pseudoC it would look like this :
gameState s; int time = 0;
int main() { load_resources();
}Switching to a functional language, a way of thinking about the game flow I've found useful is this :
The main loop becomes a function of two parameters : the current game state and the current inputs. From these it computes the next state. After the current simulation tick has passed, the next game state become the current one, whatever video and audio you have is updated and new inputs are gathered. It would look like this :
int main() { game_loop(load_resources(),init_inputs(),0); }
gameState game_loop(gameState currentState, gameInput inputs, int game_time) { render_video(currentState); render_audio(currentState);
}Yeah, in C it will blow your stack, but functional languages have to deal with recursion much more often, and what you see there will be optimised away to a loop and be executed in constant space.
Other things to note are that you see the state passed explicitly between functions (no relying on it inherently existing as a global) and that the shift is from modifing an object as the game progresses, to creating a new object to represent the new state of the world, and discarding the old one.
Languages, be it lisp, haskell, calm, scala, f# or python, java, c, c# (used as functional languages) are relatively easy to learn. What's hard is adapting your thinking to the strengths and limitations imposed by them.
Hope this helped.
Start here maybe? http://shiny-dynamics.blogspot.com/2006/01/munching-on-openg...
Anyway your question was more about abstract concerns, but concretely, note there are pretty decent SDL and OpenGL bindings for common lisp, and mildly optimised native compiled lisp code borders on "fast enough" for fast-paced 3D games - I mean people write fun games in Python these days, never mind lisp! even if GC is not concurrent, GC pausing is much less of a problem than people make out with a little common sense and care, - prealloc object pools before levels begin, code consless or at least cons-lightly, perhaps even go ahead and disable GC runs except at inter-level breaks...
IMO CLOS is a very nice object system for game code in an object-oriented style due to multiple dispatch (see wikipedia example):
http://en.wikipedia.org/wiki/Multiple_dispatch#Common_Lisp
http://lispbuilder.sourceforge.net/lispbuilder-sdl.html
http://common-lisp.net/project/cl-opengl/
When I last looked a while back (it might be neater now), the secret to getting cl-opengl and lispbuilder-sdl to play nice together was the following incantation, enabling use of opengl 2 shaders and stuff:
If you wanted to make a game in Haskell, which is purely functional, then your concerns would be more appropriate.
And by the way, you won't be able to do pure functional game programming in any language. At some point you'll have to bottom out in modifying display state - whether opengl calls, or directx calls, or flash display list changes.
Writing in a functional way allows you to express algorithms more easily than you could otherwise. At any given point, while doing something functionally, you only need be concerned about the state of your inputs and your output(s). Letting go of state frees your mind from worrying about so many variables, and it allows you to think about the algorithms more easily. Of course, it may take a while to start to think about things functionally, but you'll have that any time you are learning something new.
Another benefit is it makes things easily concurrent, which is a large challenge for the game industry at large. Caveat -- make sure you know how your language/implementation deals with this, however. Erlang is much different than Common Lisp in this regard, for example (unless there is a specific CL language with threads that I don't know about).
BTW, basically every lisp you'd ever use has objects, or multimethods http://clojure.org/multimethods << basically the same thing, as far as it matters.
Thus, Lisp, ML, etc allow you to use FP whenever it is beneficial, and allow you to confine your state changes such that you won't have to worry about them nearly as much. Thus, many fewer bugs.
I cannot encourage you enough to continue to look into this. My only concern is that you will run into a lack of libraries, which clojure addresses, as everyone has already mentioned.
http://common-lisp.net/project/pal/
It even has a game written in it already:
http://www.cliki.net/Bermuda
I use SBCL with lambda-gtk, lispbuilder-SDL and CL-OpenGL. Couldn't be happier. And oh, on Win32 and Linux :-)
http://clean.cs.ru.nl/About_Clean/Platform_Games/platform_ga...
Haskell has "state", but uses monads (design patterns derived from the type system) to segregate it carefully. Clojure has state, though "variables" are immutable by default and state requires the use of special concurrency-safe features.