Hi!

I'm making a game with Clojure. And I have a few code structure/design
problems.

I have an atom with characters (a map of maps) in my main file. But
because I don't want to make that file too big I have, for example, a
file called "ai.clj" with AI stuff, that I require from the main file.
For the monsters' AI to work, the AI needs to know the state of the
world, i.e. the characters. My current solution is to (declare
characters) and then have a
(defn init-ai [characters] (def characters characters))
function in ai.clj that I call from the main file at the start of the
game. It works, but it doesn't feel quite right. I don't want to have
to pass the characters as an argument all the time, that seems a
little bit too verbose to me. It seems somehow unnecessary to have to
just pass the same atom around to all the functions.

That's a general theme in my project: modules/files depend on the main
module/file. And sometimes there's nothing I can do about it. The
graphics engine I'm using, for example, insists that my application
extends an "Application" class from the engine. And that the main loop
is in that "app". So that's in my main file. But I really want the
graphics module to be a separate thing to which I send things to be
represented graphically. But, of course, the graphics module depends
on the "app" instance in my main file. So I did for the graphics what
I did for the AI.

Another concern of mine is that there are so many places where I need
to update the characters' state. There's the AI stuff, that updates
the monsters with their targets and paths, etc. Other examples: when
one character attacks another, then the health needs updating; or when
the player moves. I have a doubts that I am doing this "the Clojure
way."

Often, the characters' ids are arguments to functions. For example, I
have a function called physical-attack (the one I mentioned above)
that takes the id of the attacker and the id of the target. Then it
calculates how much damage the attack is supposed to do, and updates
the target's health in the 'characters' atom. Sure, it could return
the amount of damage instead, that would be one step towards purity.
But to be really pure it would have to take the actual maps as
arguments too. It may work in this case, but it's not always so easy
to make the functions pure. The function that calls physical-attack,
for example, also updates the attacker (he now has to wait before he
can attack again), and returning both of the updated characters is not
as nice as returning one. And the update still has to happen
somewhere, because attacking *has* a side effect (in the game), so
maybe it's ok. It's just that now the updates are spread out all over,
and I thought that maybe it was better to have them in a special place
in the code, for sturcture and sanity.

A concrete problem: I want a function that takes the ids of two
characters (because as I explained above that's more convenient) and
checks if they are close enough to each other to attack. But I want to
use the function in the ai file and in the main file. But I can't
define it in some sort of utility file, because it depends on the
characters atom. And it doesn't feel quite right to define it in
ai.clj since 'characters' is defined in the main file, but the main
file requires ai and not the other way around. I could also define the
function in the main file and send it to the ai file as I did with
'characters' itself, but that seems really messy. Sure, this function
could be functional, and that would solve these problems. But that
would be inconvenient, because I would just have to look up the
position of the characters in a lot more places instead, leading to
increased code size.

I just wanted to write down my problems and maybe get some comments on
it. This being my first real Clojure project, I feel that I could use
some guidance, so feel free to comment as much as you'd like. I
realize that these are problems programmers deal with all the time (at
least I think so), but I thought that maybe the Clojure community,
being so wise, might have some answers. ;)

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