Saturday, June 16, 2012

Terrain Discovery

I implemented terrain discovery based on the people's locations.  Right now it just uses a cheap range calculation around the person's location, so it is possible for them to see things even if they don't have a line-of-sight on it.

As always, find the latest revision at

Here is the function (found in /src/model/update.clj) that determines the visibility from a given location:

(defn- visibility [[x y z]]
  (let [h-range (range -6 7)
        (for [dx h-range dy h-range dz [-2 -1 0 1 2]
              :let [x (+ x dx) y (+ y dy) z (+ z dz)]
              :when (< (+ (* dx dx) (* dy dy) (* dz dz)) 36)]
          [x y z])]
    (zipmap nodes (map (partial world-get @wrld) nodes))))

It's quite terse, but don't let that scare you.  The first line takes a location as a parameter, and deconstructs it into x,y,z coordinates.  Next, it creates h-range, where (range -6 7) is just short for [-6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6].  Those are the horizontal coordinates relative to the viewer.  The "for" statement evaluates for every possible combination of relative coordinates that we're interested in, from -6,-6,-2 all the way to 6,6,2.  These are filtered using the distance formula (so that visibility has a radius of 6, rather than being a square)

Finally, all of the coordinates that meet the criteria are used to pull information from the world.

One thing you could play with is the visibility range and radius.  For example, if you want to change horizontal visibility from 6 to 20, change (range -6 7) to (range -20 21), and change 36 to 400 (that's 20 squared).  Or, if you want them to be aware of several layers in the ground beneath them, change dz [-2 -1 0 1 2] to dz (range -20 2)


  1. Hi

    I want to add your blog to Planet Clojure - can you add some label, for example, clojure, to clojure-related posts?

  2. Hey Alex,

    Thanks a bunch for reaching out to me! I've actually been kind of nervous about getting much notice from the clojure community, since I'm learning as I go and I'm mostly just rapid prototyping. The project is quite hacky right now (hence the name of the blog) and has lots of non-idiomatic clojure.

    On the other hand it would probably be good for me to get feedback from the community, and maybe even pick up another programmer or two, so really I'd love to be listed on Planet Clojure. As of now the blog is entirely about the game that I'm developing with my brother and nephew (trying to teach them programming along the way), so all of the posts are clojure-related. I'm not sure how necessary it would be to tag the posts, but I can do it if you still think it would be helpful.

  3. I also think, that feedback from community will be helpful ;-)
    If the blog will continue to stay all clojure-related, then I will add it right now as-is, without filtering...
    P.S. blog will be synced to planet in around half hour

  4. Hi,

    Which versions of the libs are you using? Because I've tried to use the project on a mac and the native libraries are missing.

    Thanks !!

    Juan Manuel

    1. Hi Juan,

      You're the first person to tell me about trying it on Mac - after reading your message I updated to the latest lwjgl and included the mac natives. I don't have a way to test it, please let me know if you get it to work.


    2. I've pulled your changes and it works !! You only have to change run-sh and select the macosx native libraries.


      Juan Manuel

    3. Nice! I figured it wouldn't be too much trouble to get it working on Mac... now to decide if there's a way to make work for both, or to write two shell scripts (one for each OS), or maybe there's a better solution that I haven't thought of yet.

    4. You can change to:

      # OSTYPE is set by bash
      case $OSTYPE in
      darwin* )
      platform="macosx" ;;
      * )
      platform="linux" ;;

      java -cp "./src:./build:./lib/clojure-1.3.0.jar:./lib/toxiclibscore.jar:./lib/slick.jar:lib/jogg-0.0.7.jar:lib/lwjgl.jar" -Djava.library.path="lib/native/$platform" clojure.main src/terra-incognita.clj

    5. Done! Please pull the latest to verify that it works.