Plasticine architecture

A patafungi building site for the Aniziz game. The shapes have been inspired by Siteless – an architectural book I absolutely love by François Blanciak. It contains 1000 ideas for building forms inspired by time spent in different cities around the world. This could be a great starting point for all kinds of ideas for levels, worlds or objects in many types of games.

The forms, drawn freehand (to avoid software-specific shapes) but from a constant viewing angle, are presented twelve to a page, with no scale, order, or end to the series.

Algorithmic fungi patterns

Central to the borrowed scenery game is an ecosystem of fungi that players will grow to feed the plants found by foragers in the city of Ghent using Boskoi. These fungi will work differently from the plants in Germination X, partly in response to some interesting game testing feedback – the fungi will only grow to the next stage when activated by a player, but the positions of new fungi will be algorithmically decided.

This calls on a kind of cellular automata, which requires a bit of prototyping to get the right values to make the kind of patterns I want. I mocked up something in clojure (so I can plug it into the game server easily) using ascii art for previewing the patterns resulting, the four stages of fungi are:

. : spore
o : young
O : adult
* : fruiting

Each fungi cell only goes from adult to fruiting if conditions are right (counting number of neighbours as in the game of life), after which 5 spores are created around it. After fruiting or adult stage the fungi dies and gets removed. This is a screenshot showing some different colonies which emerge starting with just two fungi spores:

                     .Ooo*.                o..O   
                     o*o ..                 *.O   
                      ..*.                 o*oo.  
                       ...                 .*OOoo 
                                            ..Oo  
                  O o                       ..*.  
                  O                            o  
              O       o                           
                oO                                
            .O                                    
           O*                                     
           oO..                                   
         o  o *.OO                                
             ..O                O O               
              ** o                O               
             .*..o              OooO              
             .o.*.             .oOO*O O           
               . .              ..O*O O.          
                                O*. O*o*.         
                                Oo OoO. .     

And here is the code:

(def *spore-count* 5)
(def *neighbour-distance* 15)
(def *max-neighbour* 60)
(def *min-neighbour* 0)

(defn make-cell-world [cells]
  {:cells cells})

(defn make-cell [x y]
  {:x x :y y
   :state "."})

(defn cell-dist [cell-a cell-b]
  (let [v {:x (- (:x cell-a) (:x cell-b))
           :y (- (:y cell-a) (:y cell-b))}]
    (Math/sqrt (+ (* (:x v) (:x v))
                  (* (:y v) (:y v))))))

(defn cell-process [cell neighbours]
  (if (< 50 (rand-int 100))
    (cond
     (= (:state cell) ".") (merge cell {:state "o"})
     (= (:state cell) "o") (merge cell {:state "O"})
     (= (:state cell) "O") (if (and (< (count neighbours) *max-neighbour*)
                                    (> (count neighbours) *min-neighbour*))
                             (merge cell {:state "*"})
                             (merge cell {:state "X"}))
     (= (:state cell) "*") (merge cell {:state "X"})
     :else cell)
    cell))

(defn cell-get-neighbours [world cell]
  (filter
   (fn [other]
     (< (cell-dist other cell) *neighbour-distance*))
   (:cells world)))

(defn cells-find [world x y]
  (filter
   (fn [cell] (and (= (:x cell) x)
                   (= (:y cell) y)))
   (:cells world)))

(defn cells-make-rnd-pos-list [cell]
  (repeatedly
   *spore-count*
   (fn [] {:x (+ (:x cell) (- (rand-int 3) 1))
           :y (+ (:y cell) (- (rand-int 3) 1))})))

(defn cells-spore [world]
  (merge world {:cells
                (concat
                 (reduce
                  (fn [r cell]
                    (if (= (:state cell) "*")
                      (reduce
                        (fn [r pos]
                          (if (empty? (cells-find world (:x pos) (:y pos)))
                            (cons (make-cell (:x pos) (:y pos)) r)
                            r))
                        r
                        (cells-make-rnd-pos-list cell))
                      r))
                  ()
                  (:cells world))
                 (:cells world))}))

(defn cells-death [world]
  (merge world {:cells
                (filter
                 (fn [cell]
                   (not (= (:state cell) "X")))
                 (:cells world))}))

(defn cells-run [world]
  (cells-death
   (cells-spore
    (merge world {:cells
                  (map
                   (fn [cell]
                     (cell-process cell (cell-get-neighbours world cell)))
                   (:cells world))}))))

(defn cell-world-print [world w h]
  (dotimes [sy h]
    (dotimes [sx w]
      (let [f (cells-find world sx sy)]
        (if (> (count f) 0)
          (print (:state (first f)))
          (print " "))))
    (print "\n")))

(defn cell-world-loop [world n]
  (println "-------------------------------------------------")
  (cell-world-print world 50 20)
  (when (> n 0)
    (recur (cells-run world) (- n 1))))


(defn -main []
  (cell-world-loop
   (make-cell-world (list
                     (make-cell 25 10)
                     (make-cell 27 10)))
   1000))

Clay mushrooms

More work on the Borrowed Scenery project and a first screenshot, experimenting with different visual styles. I’m trying modelling clay to get a 3D look on the fungi and using Theun Karelse’s mockup characters for player avatars. The floor is being built out of map tiles of Ghent pulled from OpenStreetMap, using the OpenLayers API which has been pretty fast to get running.

A lot is changing with code too, the client graphics are now entirely HTML5 canvas, the server is running a modified version of the Germination X game, switched to using websockets and upgraded versions of all the clojure libs.