0
votes

I have a small Clojure game (think Snake but multiplayer; if you hit another snake, you lose) running over WebSockets - logic is in the Clojure backend, rendering is in the browser.

Every "turn" of the game takes 100ms, during which the game steps, which involves 1) calculating the next state of the game, 2) sending the game state to every player over WebSockets 3) checking if the game is over, and if not 4) sleeping for 100ms minus the time it took to do steps 1-3, and 5) looping back to 1.

There is a global atom games, which is a map from a UUID to a game map (has player coordinates, directions, etc.). When a player presses an arrow key, the browser sends a message containing the game's UUID, the player's UUID, and the move. On receiving that message (independent of the game loop), the server directly modifies the games atom to update its to-moves map to say that the player with some UUID wants to turn :right. Step 1) above takes the to-moves list and changes each players' directions accordingly before moving each player forward (every 100ms). This method works.

I learned about core.async (go, channels, parking, etc.) but I'm not sure if it would be applicable in this case. I was originally thinking that instead of a :to-moves map as part of the Game, I have a buffered channel instead. Then when a player submits a move I can do (>!! ch [<player-uuid> :left]), for example. And when I calculate the next game, I can get the moves with (

This is more of a learning project, so if core.async will pretty much be the same as my current method that's fine. But is it applicable in the first place?

Thanks.

1

1 Answers

0
votes

Firstly, I'm assuming that when you say "running over websockets" you mean that you're running ClojureScript in the browser and that you want to use core.async in the browser to decouple your websocket communication implementation from the event generation.

In that case, core.async channels is a very neat fit since you can setup your websocket as a consumer on a channel and pass that to all the pieces like the keyboard event listeners to write to.

It also lets you then setup an outgoing channel that you can cleanly hook up to your game state and make the changes received from the server into the atom.

The point of it is to introduce the decoupling so that as long as you implement some kind of thing that gives you an input and output channel, it'll work. You could replace the websocket implementation with a dummy test or replace the events and game state management with simple listeners and emitters so you have a nice seam to isolate bugs with.