Entity-component-system in Clojure
I have been working on this library, clecs, for a couple of months. It is an entity-component-system (ECS for short) implementation in Clojure. And it is definitely not production ready yet. This is not going to be a tutorial but I’d like to go over some decisions/discoveries related to clecs and ECS in general.
One API Many Backends
I didn’t intend to support multiple implementations from the beginning. See, this is one of the strengths of Clojure; it leads you to design your code for extensibility by its design. Not long after I started writing the protocol, there was just one in the beginning, I realized it wouldn’t be too much more work to add support for multiple backends.
And multiple backends is not a bullet point feature either. I want to create a library to make writing games in Clojure simple. But I don’t want to do this by locking those games up with the trade-offs I have made. Or perhaps I should say I don’t want only those few who are OK with the trade-off I have made to use my library. It doesn’t take long to realize some open source software is going to be a liability down the line.
So clecs support multiple backends, users get to choose what is important and what can be sacrificed. A fast paced game can use an in-memory world and a massively multiplayer online game can choose to persist its data in a database cluster. The important point here is that there is one API. When you are writing your application code you shouldn’t worry about the underlying data structure or persistence scheme.
There is no hosted API documentation yet, but you can check out the API here.
Why the Rebellious License?
You have all heard the stories about the developer who refused to license his Clojure software with EPL. How they are taken in black cars with black tinted windows by mysterious men in black. Disappeared and never seen again. Well, I am here to tell you all that you have heard is... none of it is true.
But it is true that licensing with EPL is encouraged in Clojure community. Because it makes sense for components in a software ecosystem to use compatible licenses. I had an issue with the following part of the EPL license:
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America.
I decided to go with the GPL license. I have added the exception mentioned in section 7 for Clojure. This makes clecs’ license compatible with Clojure’s. I am not planning to change the license, even to LGPL, anytime soon. But I would be happy to add more exceptions if necessary/beneficial.
There is one big and one relatively smaller task ahead, in the programming department.
The latter is to refactor query sub-system. Currently you pass a filter function which will be passed a seq of components for each entity. This works well enough for the reference implementation. But it will definitely fail to perform for worlds with many (millions?) entities. The function needs to be replaced with some sort of data structure that defines the query. Then backends can take this and do specific optimizations.
The bigger task is to create a generative test suite to test backends. The idea is to treat worlds as black-boxes and run a series of randomly generated operations on them and compare the results to expected results. This is going to be tricky because there are actually three contextual levels... Wait, before that, this is going to be tricky because worlds are mutable and we are interested in how these data mutations interact with each other. So our tests are not unit-tests. And there are three contextual levels. Think of atomic transactions, and within a transaction you run something like a transaction that you can only run within a transaction and then there are some commands that are available only outside of a transaction. I know it sounds like mad talk, but check out world.clj and you’ll see what I mean. I am not mad.
Critics and Comments Welcome!
There are no decent documentation yet. There is an example project but I think it’s not enough and anyone interested still needs to check out the source.
This is a phrase I used and have seen being used many times in communities of 3D artists speficically Blender community: critics and comments welcome. There is not much to help with the project at this time but if you can take a look and at least tell me about your first impressions it would be great. I have two main questions:
- Do you think having a game development library that is completely agnostic about rendering, sound & inputs, i.e. doesn’t provide any of these, make sense?
- Do you think the API looks right? Is it idiomatic Clojure from a library user’s perspective?
If you have any questions, suggestions or corrections feel free to drop me a line.