Fork me on GitHub
#clojure-gamedev
<
2023-07-26
>
markx04:07:00

@mx2000 I always have this question on how to manage Java objects when using Java libs, e.g. libgdx. I wonder how you deal with this: Normally in Clojure we use a map (maybe in an atom) to model the states, use pure functions to transform the map, and push any side-effect, e,g, rendering, to the "edge" of the app. In the example of libgdx, rendering means you would create some Java objects, like Sprite. The problem is, we can't just create tons of Java objects from the state map for every entity for one-time use each render loop, and throw away after, right? That'll be too many objects? So instead, maybe I just keep the Java objects in the state map? but then they are not immutable data so it's inconvenient to transform them with pure functions.

mx200005:07:22

I just try to avoid it as best as possible to use mutable objects. For example I am not using the libgdx Sprite class, but have created an image record which holds just a Texture region (which I don't mutate) https://github.com/damn/gdl/blob/main/src/gdl/graphics/image.clj Also I wrote my own immutable animation class, it's not much code https://github.com/damn/gdl/blob/main/src/gdl/graphics/animation.clj I guess it depends, for example I am using libgdx scene2d ui and just going along with the state management there because there is no alternative for the UI (windows, buttons, etc.)

Joshua Suskalo14:07:09

So that idea of 'too many objects' is missing something. Every single clojure operation on data structures is new-ing up objects. The JVM is incredibly good at collecting objects. The real concern is if the objects being set up and destroyed have a lifecycle that must be followed or if they manage external state like gpu state.

mx200022:07:14

Hmm good point I don't know much about jvm internals. Although immutable data structures are also easier to test and understand. But good to know that doing it with a lot of objects might not be the end of the world

Joshua Suskalo22:07:20

Yeah, quantity of objects that are created and thrown away isn't much of a concern on JDK 11+, and on JDK 8 you can make it fine by setting the GC to use the G1 garbage collector

👍 2
markx23:07:52

@U5NCUG8NR thanks for explaining! That's a great point. But still, now that creating Java objects is not a problem, where do you keep them? Do you push them to the edge or do you keep them in state maps? Or something else?

Joshua Suskalo23:07:34

Ideally mutable state won't be the center of your application state

markx23:07:07

Do you consider Java objects mutable state then?

Joshua Suskalo03:07:11

if they have non-final members (or final members that are references to mutable objects) then yes

Joshua Suskalo03:07:47

that's not to say never use mutable stuff, just not to represent your primary game state.

Joshua Suskalo03:07:36

sprites and files and other resources have to be managed somehow and it's easiest to hold them in clojure data structures

Joshua Suskalo03:07:08

just don't have your actual state of game objects be mutable

markx04:07:34

Got it. Last time I interoped with some Java lib, it was so awkward! But I need to give it another try. Thank you both!

Noah Bogart13:09:33

To second Joshua’s comments, I maintain a ccg written in clojure. the game state is an atom, and the whole codebase is peppered with swap! calls. It makes debugging and testing a pain, and ruins any attempts at threading or functional style. It’s exactly the wrong way to write clojure lol

👍 1