Chicken or egg in functions / actors handling WorldState

I have read the "Purely Functional Retrographs" series

http://prog21.dadgum.com/23.html

It discusses some interesting techniques for building a (semi) clean update loop for the game world.

However, I have the following side note that I can't seem to look back:

Suppose you have a system where each enemy and each player are separate participants or separate pure functions.

Suppose they all receive "WorldState" as input and output New WorldState (or if you are thinking in acting terms, send a new WorldState to the next actor, ending with the "Game Render" actor, for example).

Then there are two ways to do it:

  • Or you start with one actor (player fi) and feed him the "current world". Then you feed the new world, the next enemy, etc., until all the actors transform the worlds. Then the last world is a new world that you can feed into the visualization loop. (or, if you followed the above article, you get a list of events that have happened in the world that can be handled).

  • The second way is to just give all active WorldState members at the same time. They generate any changes that might conflict (for example, two enemies and the player can take a coin in the same animation frame) → it is up to the game system to resolve these conflicts by handling events. When all events are processed, the game actor creates a new world that will be used in the next update frame.

I have a feeling that I just ran into the same "race condition" problem that I wanted to avoid using pure functions with immutable data.

Any advice here?

+3


source to share


2 answers


I haven't read this article, but with the coin example, you create a kind of global variable: you give a copy of the world state to all participants, and you assume that each actor will evaluate the play, make decisions and expect their action to be successful regardless of the latter. stage, which is a solution to the conflict. I wouldn't call it a racing state, but rather a "blind state", and yes, it won't work.

I assume you came to this solution in order to allow parallelism not available in solution 1. In my opinion the problem is with responsibility.

The coin must be owned by the actor (the server acting as the resource manager) like anything in the application. This actor is only responsible for what happens to the coin.



All requests (there is something to grab, to capture, to remove something ...) should be sent to this actor (one actor per cell or by map, level or any split that makes sense for the game).

How you manage it is up to you: serve all requests in order of receipt, buffer them until a synchronous message appears, and make an arbitrary decision or priority decision ... Either way, the server will be able to respond to all participants with success or failure without any or the risk of a race condition, since the server process runs (at least in erlang) on ​​one core and sends one message at a time.

+5


source


In addition to Pascal's answer, you can allow parallelization by splitting (a huge map I assume) into smaller chunks that depend on the last state (or part of it, like an edge) of its neighbors. This allows this game to be distributed among many nodes.



+2


source







All Articles