On Mon, Aug 16, 2010 at 03:43:11AM -0700, Mike Anderson wrote:
> 2. User interface comes last, which is good in general but makes it a
> royal pain to pass notifications back to the UI. In Java I would
> simply have e.g. units.clj call a simple notification function in
> interface.clj, in Clojure I can't do that because I can't mutually
> require the namespaces.... so I end up either passing a callback
> function or polling some atom, neither of which are particularly
> elegant.

It's often helpful to have one component that acts as a message bus
between the other components.

A quick and dirty example:

;;; --------------------------------------------------

;;; The message bus
(ns game.event)

;; A map storing the functions that should be called when an event
;; occurs
(def callbacks (atom {}))

;; Functions for subscribing to, and dispatching events
(defn call-when [event callback]
  ...)

(defn dispatch [event & args]
  ...)

;;; --------------------------------------------------

;;; User interface
(ns game.ui
  (:require [game.event :as event]))

;; An example of an event listener
(event/when :unit-destroyed
            (fn [unit]
              (comment Update the UI here)))

;; An example of an event dispatcher. Sends an event to be handled by
;; the component whose responsibility it is. Note that at this point
;; we don't know which component that is.
(defn request-reinforcements-button-clicked []
  (let [amount (.getValue reinforcements-amount-input-field)]
    (event/dispatch :reinforcements-requested amount)))

;;; --------------------------------------------------

I've found this approach to work quite well in game development. As
the components don't care about who reacts to the messages they send,
or who sent the messages they are interested in, it's very easy to
plug in and remove components as needed. For example, you can add a
sound component that plays appropriate sounds when events occur in the
game without requiring any changes to any other components.

This approach is especially helpful when unit testing. You can create
a new bus and plug in just the component under test, and then simulate
all the other components by sending the same messages as they do.

--
Timo

-- 
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