I am working on my first (non-trivial) Clojure program I don't really feel comfortable with how I am declaring all my mutable state globally. For example:
(def next-blocks (atom []))
(def num-next-blocks 1)
(def is-game-over (atom false))
(def user-name (atom (str)))
(def hs-xml (atom nil))
Since I use C a lot at work I came up with the idea of using common C-style encapsulation techniques. It typically involves struct object that passed as a first argument to any "member functions" that operate on it. See udev for example.
Applying this to Clojure would result in functions that look like this (untested):
(defstruct gamestate)
(defn game-new []
(struct-map gamestate
:level (atom 0)
:score (atom 0)
;etc...
))
(def game-get-score [game]
@(game :score))
(defn game-set-score [game new-score]
(reset! (game :score) new-score))
(defn game-get-level [game]
@(game :level))
(defn game-inc-level [game]
(swap! (game :level) inc))
; etc...
I think it would definitely be a step forward to the global defines that I'm using currently.
So is this the recommended way to go? Or is there a more standard Clojure way?
I'm currently using Clojure 1.1.0.
The basic idea of functional programming is that you have very few global variables but mostly local ones (see Rich Hickey's article on state and identity). Writing a game in this paradigm may be challenging, I'd recommend this post on functional programming for games (the examples are in Erlang, though).
I don't know what kind of game you want to implement. Here is a code snippet improv of what I would do with local variables.
(defn play-game [name score blocks]
(let [level (start-mission (:level score) blocks)]
(if level
(assoc score :level level)
score)))
(defn the-whole-game []
(let [name (ask-username)
score (or (load-score name) {:level 0, :score 0}]
(when-let [new-score (play-game name score [])]
(save-score name new-score))))
You may want to check out another Tetris clone in clojure, it uses opengl, though.
In my Clojure game I'm using a single atom containing a map to store all my mutable game state. This includes certain elements of the user interface state.
This is currently defined as follows:
(def state
(atom
{:game (gamefactory/make-game)
:scroll [0 0]
:mouseover [0 0]
:command-state nil
:commands (clojure.lang.PersistentQueue/EMPTY)
:animations {}
:player-id nil}))
This model is working very well for me. You can easily access the state elements directly e.g. (:game @state), or alternatively define accessor functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With