Thank you Alex and abp!

Your posts certainly contains valuable information. But I have
questions still. One might say that you explained how to use
protocols, but the questions I have left are: Why protocols (and
records)? What benefits do I get? Alex mentioned polymorphism; how is
this different from/related to multimethods?

Let's take the game example again. Say I have (which I do) a map of
characters in my game that contains both monsters and players.

A monster:
{:type :mob :pos [x y] :hp 30 :max-hp 30 :dmg 5 :name "an orc
pawn" :attacking false :last-attack 0 :attack-delay 1500 :target
nil :path nil :speed 2.5 :ai ai/attack-nearest}
A player:
{:type :player :name "Bill" :pos [0 0]  :hp 100 :max-hp 100 :dmg
10  :attacking false :last-attack 0 :attack-delay 1500 :target nil}

And I have a few things I want to do to them. Like attack, draw them,
take damage, die and respawn, etc. Right now all those things work
exactly the same way for both types. Partly because they are so
similar, but also because the game is not nearly done yet. For
example, I might want to draw them differently, or have them take
damage differently, or whatever. I use the type mostly to filter the
map, for example monsters can only attack players.

Is it a good idea to use protocols (and records?) for me in this
situation (now or in the future when I might want them to behave
differently)? How can I benefit from them?





On Jul 28, 1:46 pm, Alex Osborne <a...@meshy.org> wrote:
> 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