Fork me on GitHub

@jcromartie: I've done a lot of game programming in my past. I'm speaking more from my experience in other languages and applying what I know of Clojure, so I am sure some of what I am about to say isn't 100% true. Anyway, I don't feel Clojure is that great for games. I wish it were, but it leaves a lot to be desired due to garbage, the JVM, and tuning. Mutability is a dirty, but necessary part of most game development. If you're building a browser game or small, non-performance critical game, no problem. Otherwise, you're in for some pain, especially calling things like opengl and other libraries. Mostly my complaints are JVM related combined with additional Clojure issues, but I'm speaking from more from building larger games and working on engines. That said, where Clojure does shine in relation to game dev is that I think is it's not too hard to build a nice entity system-like pattern. In my recent code, I've modeled a lot of my architecture of what I used to do with entity systems. Game code that sees the same data structures again and again in a straight path tends to do well, so channels + threads/go-loops are good for that in theory. If you think in terms of ticks and doing that work in threads/go-loops, it's quite easy to get some beautiful looking code. You can then use multi-methods and protocols to dispatch to "system" like constructs with your other logic, which also could contain their own threads/go blocks/plain loops. Couple that with building maps as components and use atoms and such for pooling to help with the thrashing, and you have a decent architecture. You can loop through your systems and call them each tick, and modify your component maps inside each, looping and recuring with the map data if you want. You could further tune things with transients to squeeze out some more performance. Where I see some trouble with that approach is you absolutely need to be sure your processing code doesn't spend more than x time per frame or at least is able to abort pre-emptive style. It's doable with introducing a few constructs like alts, timeouts, control channels, etc. It's working for me in my code, but it's not a game. I do however use a very crude notion of a scheduler pulsing each channel I'm taking from to "wake it up" as best I can in a more deterministic fashion.


I know that's a lot and some nonsense, but hope it gets you thinking at least.


wow, @hugesandwich thanks for all of that simple_smile really!


@jcromartie: no problem. Generally, just be practical. If you want to build a game in Clojure, it's perfectly fine. But you will not be able to build a 60fps behemoth AAA quality game with no stuttering. Or at least not without great pain. Everything about C++ game dev pretty much still applies, you just have to learn it's OK to not do some things you are used to doing in Clojure. Oddly enough, game development in C, C++, and other object oriented languages is becoming highly functional. In other words, people are avoiding many of the tools in their languages to develop closer to something like Clojure. The big difference is mutability is still king in a lot of places, or until we see more architecture changes on the average consumer-facing CPU especially.


oh absolutely


I only aspire to make something like FTL or maybe Don’t Starve


that sort of level of complexity


I have some ideas for how to leverage mutability and caching


and the entity system idea is intriguing


That's doable, just be sure that you are aware of frame timing


You need to be predictable


I was thinking of an entity system based on a map of component names to maps of ids to component values


Pooling is the easiest win with Clojure


I’m not familiar with pooling in a game dev context


I’ve made pong and tetris simple_smile


well very simply...


I'd keep a fixed sized array somewhere


it's fixed size because you want to explicitly control how much stuff it can have in it and so the performance and environment is predictable


also so you can cheat and use array indicies in tricky ways


so every time you allocate a component, you will remove it from the array


when you are done with it, don't just let it fall out of scope and get gc'd


instead, put it back


If you load a level or something like in FTL, each time you load a level, init the array, and when the level ends, dispose of it


same will go for any other resources that are level specific


the point is you don't allocate on demand wherever you can avoid it


you allocate on load


and de-allocate on a transition


hence why even fast games seem to take awhile to load something


yeah, avoid malloc


allocating memory is super slow in general


that makes sense


and it will keep the JVM behaving better


so you will also need to be careful about go blocks in this regard


FTL is doable in clojure though


You may just want to write a lot of things in Java and use interop though


probably for your graphics calls


and my last tip for you will be to batch your calls as much as possible, especially for gfx, but also for other operations. So build up something with transient! then call persistent! if you want it persistent, then send it on its way rather than sending things as you create them


probably old news, but this talk on games in clojure is worth your time:


I just wrote an experiment that draws a bunch of sprites with Graphics2D, and it was really slow, and then I realized I forgot to memoize my function that called ImageIO/read


lol, the “time rewinding is really cliche at game dev conferences"


I just demoed that last night


at a game dev meetup


I’m getting way off core/async here simple_smile


but I also showed off “forking” a game from a given point


i.e. cloning the window with the current state


and continuing down a different path


and throwing away windows you don’t want


@jcromartie: well we can continue the discussion some privately if you want, feel free to msg me. Trying to keep it on topic with core.async. On a semi-related note, if you use the entity system approach I describe, you should be able to put data on channels and throw it around between threads and such if you want. The added bonus is it makes time-rewinding very easy as your game's state is 100% data. Since your entities will have components attached from a pool, it's trivial to gather them all in a single pass. This is exactly how a lot of games implement saving/loading actually.


so the same would work with time rewinding. If you use channels, it should be really easy to keep everything and play back in order or a specific rate. Also useful for things like instant replay


A lot of things like this have crossover with CQRS as well. Same train of thought. You can snapshot your game state and then compress the footprint if everything has roll-forward semantics like that.


how about #game-dev


oh, #C066UV2MV


#C066UV2MV sounds perfect