concurrency-wise, you might find useful Rich Hickey's ants simulation https://github.com/juliangamble/clojure-ants-simulation/ the relevant video where he explains it: https://www.youtube.com/watch?v=dGVqrGmwOAw (if you want the slides too, see in the comments: someone suggested google for "Must watch: Clojure concurrency")
On Mon, May 20, 2013 at 4:02 AM, Daniel P. Wright <d...@dpwright.com> wrote: > 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. > > > -- -- 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.