Hello,

I am trying to structure the game loop for a simple game in clojure,
trying to keep things pure as far as possible to get a feel for how this
would work in a functional environment.  Currently, I am working with
a message-based system, whereby various events create "messages" which I
then act on to change state.  For example:

  1. Read keypresses, generate a message for each keypress and add to
     the queue.
  2. Read from the network; add any incoming messages to the queue.
  3. Add an "update" message to the queue which can be used for generic
     update processing: AI, physics, whatever
  4. Go through the entities in my world delivering these messages as
     appropriate.  Keypress and update messages will be processed by any
     entity that implements a handler for them; network messages may be
     "directed" so that they only get sent to a specific entity.
    (The return value of the functions processing these messages is
     itself a vector of messages, such as "update-state" to replace the
     current state of an entity (position, etc) with a new state, or
     perhaps a message to send information over the network.)
  5. Send any outgoing network messages, perform any state updates, etc.
  6. Draw the screen, return to 1 and begin the next game loop.

The issue I'm having is that this system results in rather a lot of
looping through every entity in the world.  There are two full loops,
delivering the messages in step 4 and updating the state in step 5.
Originally I had the message handlers in step 4 return a new state
rather than new messages, so I just updated the entities in-place during
the first loop, but I found sometimes I wanted to do other things than
just update state -- for example send messages over the network, or to
another entity in the world.  So it seemed more flexible to return
messages, even if some of those messages are directed toward the entity
sending it.

My other issue is that with messages intended to be processed by a
particular entity, I can either check that while looping through the
whole list of entities (which means for every entity it's not intended
for I'm running a wasteful check on the id of a message), or I can put
the entities in a map instead of a vector and look them up by some id
instead (in which case I'm doing a search for every directed message, on
top of the loop I'm already doing through all the entities).

I've come from a mostly C++ background, so my sense of when I'm doing
something really bad isn't very well-tuned in functional languages at
the moment.  I write something that "feels" nice and looks pretty, and
then I step back and think about what it's actually *doing* and I can't
help but think "in C++ this would be unforgivably vile."

It seems the more I try to push function purity the more I have to loop
through some monolithic data structure holding all of my state, since I
can't just pass references around and modify them in-place.  Writing the
code for the entities themselves is going quite well -- I am keeping
their functions pure, not referring to anything outside of the
parameters they're passed in, and thus always returning the same result
given the same input, and limiting their input to the information they
need without giving them access to the entire state of everything -- all
of which is great for testing, parallelisation, and all the rest.  It's
at the higher level of managing the collection of these entities and
their relationships that I wonder whether I am working along the right
lines or whether I am in some sense "doing it wrong".

As an aside, right now I am avoiding storing entity state as atoms and
having the update functions modify those atoms because although clojure
helps update their values safely it still means the function has side
effects, and I'm trying to keep functions as "pure" as possible at least
until I can understand the limitations of doing that and see the
necessity for using global constructs.

I have a feeling this is only going to get more complex as I start
wanting to make smaller sub-lists that refer to the same entities.  For
example my entities may be stored in some tree format in the world
state, but I might want to have a list of "all enemies within a certain
radius" or whatever just as a convenience for quick access to those
entities I'm interested in.  Right now if I updated an entity in this
list it would remain not updated in the global state tree... I'm
guessing there's no way around holding an atom or similar in both lists
and updating that, but here I may be missing something also.

Sorry for the slightly rambling mail; thoughts/guidance appreciated!

-Dani.

-- 
-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to