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.