Monthly Archives: January 2011

Germination X : Hand drawn sprites and artificial life

The next revision of germination x is live, currently testing some stack overflows I’m getting with clojure, but also running a load of new stuff. I’ve replaced the old cubes the world was built from with some hand drawn ones which are slightly wonky in a pleasing way. The plants are also now running a kind of artificial life simulation where they behave according to the plants around them in a way I’m not going to explain yet.

The plants switch between predefined states for growth, decay, illness and flowering/fruiting. The current in game sprites don’t really show this to the best yet, but the code is doing the business.

Germination X – a shared garden

The live version of the game now implements a single online world shared amongst all players, and the simplest of multiplayer functionality – being able to tag your plants and see who planted the others.

Most of the work was rewriting the prototype server written in Scheme to Clojure. but I’ve also added (currently rather ugly) navigation arrows so you can move around the semi-infinite sized world-garden. Next is making the plant life a bit more engaging.

Clojure frustrations

One of the nice things about Clojure is that it comes with a huge set of data structures, all of which can be handled using normal Lisp commands. However things are not as simple as they first seem, and it’s a bit of a dark art as there is limited information online. I’ve just spent a day or so on a frustrating voyage of discovery, so I post this here in the hope of saving someone some time in the future.

Lisp generally allows you to read and write data very simply, there is no need to use a separate parser as you store information in lists – the same as the code, for which you already have a parser.

For example if you have a text file called data.txt containing ‘(“one” “two (“three” 4) 5) all you need to do is call (define d (load “data.txt”)) and it gets parsed for you from it’s text form: (first d) returns “one”. This is more efficient than using another kind of format such as XML which you’d need to run a separate chunk of code for.

One of the clojure data types I decided to use was StructMaps, which you define like this (defstruct mystructfieldone :fieldtwo :fieldthree) : and gets created like this:
(struct mystruct 1 2 “three”) => {:fieldone 1, :fieldtwo 2, :fieldthree “three”}

Clojure also comes with some handy io calls, so you can save the StructMap with (spit (struct mystruct 1 2 “three”) “data.txt”) and you get a file created containing {:fieldone 1, :fieldtwo 2, :fieldthree “three”}. This can be read back in simply by using (read-string (slurp “data.txt”)).

The catch is that the result of read-string is a different type to the object we saved:
(type (read-string (slurp “data.txt”))) => clojure.lang.PersistentArrayMap whereas: (type (struct mystruct 1 2 “three”)) => clojure.lang.PersistentStructMap. Presumably the reader interprets the curly braces as a different type. Annoying, but I then got reading about print-dup, which provides more serialisation information for recreating the data:

(print-dup (struct mystruct 1 2 “three”) *out*) => #=(clojure.lang.PersistentStructMap/create {:fieldone 1, :fieldtwo 2, :fieldthree “three”})nil

This seems to output code that should be able to recreate the StructMap. However, to actually write and read this from disk, we have to call it a bit differently:

(use ‘clojure.contrib.io)

(defn serialise [data-structure filename]
    (with-out-writer
        (java.io.File. filename)
        (binding [*print-dup* true] (prn data-structure))))

(defn deserialise [filename]
    (with-open [r (java.io.PushbackReader. (java.io.FileReader. filename))]
        (read r)))

At this point I was getting a bit frustrated, but felt I was close. Unfortunately, deserialising the file created – I got this message:

java.lang.IllegalArgumentException: No matching method found: create (NO_SOURCE_FILE:1)

Great, so the clojure.lang.PersistentStructMap/create doesn’t actually exist? More searching revealed that this is indeed the case, and is not going to be fixed in the short or medium term. Perhaps we can bump down a level and use some serialisation stuff from java – some googling provided these replacements:

(defn serialise [o filename]
    (with-open [outp (-> (java.io.File. filename) java.io.FileOutputStream. java.io.ObjectOutputStream.)]
        (.writeObject outp o)))

(defn deserialise [filename]
    (with-open [inp (-> (java.io.File. filename) java.io.FileInputStream. java.io.ObjectInputStream.)]
        (.readObject inp)))

These seem to do the trick: (type (deserialise “data.txt”)) => clojure.lang.PersistentStructMap. However data.txt is now a (relatively) large binary file, and not human readable. Not a showstopper, but all the same, not very Lisp like. I’ve been aware all this time that the documentation suggests using Records instead of StructMaps, so I assume these will work better – you create and use them in a similar way:

(defrecord myrecord [fieldone fieldtwo fieldthree])
(myrecord. 1 2 “three”) => #:user.myrecord{:fieldone 1, :fieldtwo 2, :fieldthree “three”}

However, they exhibit all the same problems as ArrayMaps when it comes to serialisation – and although they do work with the last method, they exhibit a further problem. If I change the definition of myrecord and then stream in the file, I get this:

java.io.InvalidClassException: user.myrecord; local class incompatible: stream classdesc serialVersionUID = -791607609539721003, local class serialVersionUID = 4065564404893761810 (NO_SOURCE_FILE:1)

The problem here is that I need to be able to change my structures and then convert older saved data using versioning. I can do this with StructMaps as they are not statically typed, so I can write code to check them on load and modify them to the current version (this was used a lot on NoP to keep the game running all the time with the same data while changing the fundamental types). I think a lot of my problems stem from coming from Scheme, so I’m not really aware of the “Java way”.

The other approach is to just abandon looking for an existing solution and go back to writing per-object versioned serialisation/deserialisation parsing like I do in C++.

Germination X Update

This is another very limited test version of the game, now with a plant spirit character and new plants from our concept art. The player character has gone, you can grow plants by clicking anywhere on the grass. FAtiMA is still running on the server, but it’s not connected to the plant spirit companion any more – this will come back when there is a little more going on for the characters to respond to.

The current version will generally be live and running here for you to test. The code is here.

Making game characters with a webcam

Start with a drawing of a character seperated into pieces, and show it to a webcam. An application locates all the “image islands” in the picture using OpenCV and cvBlobLib:

The image is thresholded to make an alpha channel and the images are saved. A web server (written in clojure) picks them up automatically and sends them to a flash application (written in haxe) which builds a skeleton using prims algorithm for minimum spanning tree, a port from hapstar (you make a graph of all pieces connected to all others and use the MST of that).

This automagically created skeleton can then be animated to make puppet like characters directly from drawings on paper:

Here is a more complex abstract test:

Code here and here.

Germination X – the next steps

Lina and I have begun work on the next iteration of Germination X which will be more playable than the demos we’ve been working on up till now. We are developing the look and building some of the underlying technology we need for the Pixelache event in March, lots more of this to come, but I’ve begun using the Lirec wiki to start to organise and document things.

The first part I’m looking at is getting characters drawn on paper into a multiplayer game instantly using various computer vision algorithms. This will be used in of one of our workshops at Pixelache, but we also want to prototype characters quickly and easily ourselves. Something which was lacking with the first groworld games, and I tried to address during Naked on Pluto was the effectiveness of making games shapeable by everyone involved in a project. Programming time and effort spent on this kind of accessibility seems to buy you a lot more time throughout a project even if it’s not actually seen or used by players in the end.