Oskar <oskar.kv...@gmail.com> writes:

> I have not heard much about records and protocols. What is a typical
> use case in idiomatic Clojure code for them? Is it a good idea, for
> example, to make a "Character" protocol and "Player" and "Monster"
> records or something in a game. It feels a bit too much like OOP for
> me to be comfortable with it, but I can't immediately see why that
> would be bad. I just don't know how they are supposed to be used.

The primary purpose of protocols is efficient, extensible polymorphism:
handling different data types using a uniform interface.

Rather than a composite idea like "Character" it is preferable to use
many fine-grained protocols that each cover a single indivisible
concept.  Depending on the mechanics in your game you might have
protocols like Damagable, Listener, Throwable, Describable, Capturable,
Clickable, Edible, Castable and Container.

    (defprotocol Damagable
      (alive? [damagable])
      (damage [damagable weapon]))

    (defprotocol Describable
      (describe [describable]))

    (defrecord Monster [strength color]
      Damagable
        (alive? [m] (pos? health)
        (damage [m weapon] (update-in m [:health] - (weapon :power))))
      Describable
        (describe [m] (str (if (> health 90) "a healthy " "an injured ")
                           (if (> strength 50) "powerful " "weak ")
                           color " monster")))

    (defrecord Tree [age species]
      Describable
        (describe [t] (str (when (> age 100) "an ancient " "a ")
                           species " tree")))

One of the lovely things about protocols is that they are very
extensible.  Suppose you want to write some graphics code for drawing
different game entities.  You can define a rendering protocol and extend
it to your entities all in a different file.  You don't have to clutter
up your game logic files with the ugly drawing code.

    ;; gfx.clj

    (ns game.gfx
      (:require [game.enemies :as enemies]
                [game.scenary :as scenary]))

    (defprotocol Renderable
      (paint [x canvas])
      (pixel-width [x]))

    (extend-protocol Renderable
      scenary/Rock
        (paint [tree canvas] (blit canvas "rock.png"))
        (pixel-width [tree] 30)
      scenary/Tree
        (paint [tree canvas] (blit canvas "tree.png"))
        (pixel-width [tree] 150)
      enemies/Monster
        (paint [m canvas] (blit canvas (get icons (:activity m))))
        (pixel-width [m] 70))

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to