Fork me on GitHub
#clojure-gamedev
<
2021-08-24
>
chepprey01:08:49

Is mutating a global state atom incompatible with pure functions? Or perhaps I should ask, how was it an issue in your original design?

pavlosmelissinos07:08:03

Disclaimer: I don't have any serious experience with game design yet in Clojure. You can keep your logic pure and add a thin layer on top of that to interact with state. That's probably an OK strategy. If you're working in clojurescript, something like reagent/re-frame might be an obvious choice since it offers a structured way of managing state. Mixing mutations with game logic seems like a bad idea though. It makes writing tests and debugging harder. I wouldn't even attempt making a game like that.

☝️ 3
chepprey12:08:46

I should have added @nbtheduke in my question since it was directed towards his comment about his game design, I wasn't asking a general question...

chepprey12:08:25

... Where he said he wanted to build game logic on pure functions instead of mutating global atom state.

chepprey12:08:20

And I'm just wondering about those two ideas being in conflict, because I kinda don't see it that way. Global atom carrying state, render a view based on that state. Take user input, use pure functions to calculate next frame, atomically swap in updated state to atom, repeat.

Noah Bogart12:08:23

I shouldn’t have said global, the state atom is at least passed into each function. The issue arises when swap! is called within multiple functions, mutating as actions are handled. So yes, derefing the atom and calling pure functions on state map would be good, but instead the whole atom is passed into each function and they perform individual swaps as they go: adding to the turn-events, gaining currency, writing to the log, moving the played card around, etc.

chepprey17:08:28

Ahhh I see. Thanks. Fwiw, most of my game coding experience is in 6502 assembly on a commodore vic20 😆 so, no clojure there heh

Kelsey Sorrels22:08:28

@nbtheduke this problem is familiar to me, but I don't have much good advice. My experience with this is limited to roguelike development where most (but not all) state updating happens after a keypress. In that case, it's fairly easy to pass around a derefed gamestate and return a gamestate from each function. There are subtle performance implications depending on how the gamestate is organized so a wide-flat state in some ways is preferable to a narrow-deep state, but for the most part it works very well. The major complication, of course, is adding support for animations and simulations. I've done it, but I wouldn't say the design is anything to be proud of.

Chris McCormick05:08:08

I am realizing I really need to re-write my roguelike template code in cljs. So many use-after-free and mutation issues in my current js game. 😭

Noah Bogart10:08:50

Use after free in javascript? That’s surprising!

3
chepprey13:08:59

Years ago I worked on a java project where some monster built an object pooling system into our product. And naturally it was filled with horrible race conditions, and leaked references to freed objects.

Noah Bogart13:08:44

That’s brutal

chepprey13:08:56

I guess in 2006 the JVM was not quite as well regarded as now. Hurr durr garbage collection is slow, etc. Still. When that dude left the company our team literally had a party wiping that trash out of the code.

Chris McCormick09:08:51

@nbtheduke maybe I'm using the wrong name. Basically a JS object has a key that is pointing to something, and then that something is delete, and later a bit of code tries to use the thing via the key but it's not there any more.

Chris McCormick09:08:51

@nbtheduke maybe I'm using the wrong name. Basically a JS object has a key that is pointing to something, and then that something is delete, and later a bit of code tries to use the thing via the key but it's not there any more.