Category Archives: groworld

Borrowed Scenery – spacesuits for plants and full screen scrolling in HTML5 canvas

Lots more of Theun’s new artwork which is coming on quickly over the last few days has been added to the game, the glass bubbles (more precisely cloches) are space suits for the plants from our world to live in, in their new patabotanical environment. Information about tagged plants is printed in a Voinych Manuscript inspired font.

I’ve been doing a bit more research into HTML5 canvas, turns out the the screen size doesn’t affect rendering framerate too much, and it now adapts to the browser size. Full screen scrolling is working – centring the view on the player. It wasn’t immediately obvious how this could be done without redrawing all the sprites each frame (which is way too slow), in this respect HTML5 development is really reminding me of 16bit era – hacking things like this to work quickly. It turns out it’s possible to use drawImage using the current canvas as it’s own input – so redrawing the whole thing with an offset:

function scroll(diff_x,diff_y) {
    // calculate the source and destination offsets - whether we offset
    // the source or destination rectangle depends on which direction 
    // we are travelling in 
    var sx=0;
    var dx=diff_x;
    var width=this.ctx.canvas.width-diff_x;
    if (diff_x<0) {
        sx=-diff_x;
        dx=0;
        width=this.ctx.canvas.width+diff_x;
    }
        
    var sy=0;
    var dy=diff_y;
    var height=this.ctx.canvas.height-diff_y;
    if (diff_y<0) {
        sy=-diff_y;
        dy=0;
        height=this.ctx.canvas.height+diff_y;
    }

    // remember to convert to ints, subpixel 
    // scrolling results in crazy artifacts
    this.ctx.drawImage(this.ctx.canvas,
                       ~~(sx),~~(sy),~~(width),~~(height),
                       ~~(dx),~~(dy),~~(width),~~(height));
}

Borrowed Scenery tendrils reach out

Some serious connecting work going on with borrowed scenery for joining physical and imaginary worlds together. A new Boskoi database is up and running, giving us a place to put all kinds of story elements and plants found in the city. Boskoi uses the Ushahidi platform, which provides an API the game is now using to pull all items tagged in the map (which can come from the Android app or web app) into the game where they can interact with players or other entities.

More of Theun’s artwork has gone in, including a magician tarot avatar on the left while the three plants in the screenshot above represent those tagged on the map below. Getting everything in the right place (map lat/long coordinates vs game location coordinates and then aligning the map) took a lot of time to get right!

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.

Borrowed Scenery 1.0 – joining imaginary and physical spaces

FoAM is building a story for Electrified III: The Responsive City in Ghent in September. It’s called Borrowed Scenery 1.0 and follows on from our previous Borrowed Scenery 0.1 in the same city in 2009. The story will be built out of parts arising and inspired from the groworld project – human plant interfaces, but with a focus on physical narratives and alternate realities based in the city.

One of my tasks is to take two of our existing projects, Germination X and Boskoi and bring them together – absorbing the physical space of a city into an online game, as well as using a mobile foraging application as a way to propagate pieces of the overall story. This is a good chance to prototype some ideas for combining imaginary online spaces with physical spaces, online players from all over the world and people foraging in the streets of Ghent.

I’m starting with the game, and a working sketch using Maja’s visual references for inspiration – some of the ideas here include:

  1. Representing plants found by Boskoi foragers as characters – the bubble plants with feet are the plants from our world in the game’s reality.
  2. Using the map of the city as terrain – which becomes deformed by the activity of players.
  3. Mixing different styles, organic and digital elements – but focusing on sculptural and 3D objects (rather than Germination X’s mainly 2D look).
  4. Use of many more minor and major characters (e.g. the chicken in the lower left).
  5. Use of Lingua Ignota – the “unknown language” of Saint Hildegard of Bingen, who’s viriditas or ‘greenness’ is an important element of this story (the pope is also making her the 35th “Doctor of the Church” on the 7th October, while the festival is happening).

Further ingredients will include the music of Stevie Wishart, plenty of patabotany and a good dose of tarot.

Drawing plant spirits in Brussels

Some pictures from the Germination X plant spirit drawing workshop, part of FoAM‘s contribution to Open House Brussels, a public invitation for people to visit the artistic groups and labs in the city.

The plant spirit drawing system has improved a bit from last year’s workshop at Pixelache Helsinki, being able to upload to the public server. It was great to see these spirits in the latest version (some of them are still frolicking in the game at the moment).


Next week: Plant spirit drawing & social network livecoding

The next few days are going to be hectic – a train powered scramble between cities for various activities.

Firstly I’m taking part in FoAM’s Open House event on Saturday in Brussels:

Enter a rarity cabinet of people and experiments: a lively display of human-plant hybrids, tasty table conversations, crisis-proof clothing and other curios in their natural habitat – the FoAM lab. Expect to experience a colourful collection of sketches and prototypes in various stages of completion, providing an insight into the collaborative and creative processes developed at FoAM.

My part is going to involve various experiments with Germination X, some playtesting and getting more feedback so I can evaluate the mandrake avatar changes. I’ve also rebuilt the code for “draw your own plant spirit” – this time we can directly upload people’s drawings to the public server for testing their spirit designs in the game.

The second event I’m taking part in is Baltan Laboratories The Tool Series #5: FaceSponge Workshop with Aymeric Mansoux in Eindhoven on Wednesday 23rd. We’ll be examining and exploring our real data on social networks, looking behind the interfaces and protocols we are supposed to see, with a top secret collaborative social network livecoding interface which has emerged from the Naked on Pluto project.

Germination X: Player characters

After another code sprint on Germination X, I’ve added player characters (avatars) to the game. Based on the falmouth focus group feedback this seemed one of the major things missing that players felt would improve the game.

The character design came from the Mandrake plant, which has been cropping up in groworld projects for some time – as a magical plant known to resemble human forms as it grows.

This change also allowed a much needed clean up and decluttering of the user interface for the game – as navigation now happens by moving your mandrake around by clicking on things. Your location is persistent, so when you log in you go back to the same place. All existing players in the game have been given mandrakes scattered around the world.

As the mandrakes represented a new type of entity in the world, able to move around, and linked to players – this was quite a lot of work, particularly in terms of updating the existing database. I had a lot of trouble doing this manually with MongoDB’s save command in the script interface. This seemed to be creating duplicate records (and creating very hard to track down bugs) that took a long time to find. The better approach seems to be to upgrade the database automatically in the game code, by checking a stored version number – and mapping over entries like this:

;; map over each player in the db
(db-map!
 (fn [player]
   (println "upgrading" (:name player) "to include tile and avatar")     
   ;; get a random tile in the world
   (let [tile (first (db-get-random-one :tiles {}))]
     (db-update! ;; update it, adding an avatar
      :tiles tile
      (merge tile {:entities
                   (cons (make-avatar
                          (:id player)
                          (:name player)
                          (make-vec2      ;; random position
                           (rand-int 5)   ;; in the tile
                           (rand-int 5))
                          (:layer player) ;; show the player's score on the avatar
                          (count (:flowered-plants player)))
                         (:entities tile))}))
     ;; add the tile location to the player
     ;; so we can find the avatar again
     (merge player {:tile (:pos tile)})))
 :players)

This also means that the latest code will work with snapshots I’ve taken of the game world regardless of how old they are. This turns out to be really important – I can try some changes and rewind the whole world back to the same starting point, as well as testing code locally on a copy of the current public world version.