• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

How to deal with the lack of classes prior to 2.3 and lightweight objects

mcdreamer

Member
I see that "lightweight objects" and other essentials are coming to GML in the next major point release and I'm I'm really looking forward to it. However, I'm writing projects right now and need to live with what we currently have (FWIW I don't think GML is particularly bad but I'm excited about the upcoming improvements).

In my latest RPG project, I just want some simple classes to describe the party characters and their stats, classes to drive turn based battles etc. None of these have instances directly in a scene and on top of that, things like the character information needs to persist across some (but not all) scenes.

I have this working using a combination of ds maps, indexed using an enum with names for each of the "class members" and then I have scripts prefixed with the "class" name which take the object to operate on as the first parameter to simulate member functions. Essentially I'm taking a C style approach to classes.

Is this how people generally do things? Am I missing a trick? For objects with instances in a room none of this is really a problem but obviously sometimes you want code which lives outside of these.
 

kraifpatrik

(edited)
GameMaker Dev.
Hey there! Personally I have been using the approach you describe for years now, except for the enum part, because I just find that too tedious. If you are interested, I have created an entire class system including inheritance, casting, methods, super etc. using ds maps in my open source extension. You can find it here on the forums: https://forum.yoyogames.com/index.php?threads/62585/ EDIT: If you scroll down a bit you can find there an example of what a code using the class system looks like
 
Last edited:
H

Homunculus

Guest
ds_maps, arrays, or other data structures are generally my approach as well. Data structures are decoupled from any instance and therefore unaffected by events and room changes, and their destruction / creation is under my control. If you are using enums as index though, you may consider using an array, there's no benefit in having a map if you access it this way instead of using strings, unless you are in fact using other features like json serialization.
 

NightFrost

Member
Arrays + enumerators has been my go-to for organizing data a good while now. If there's lots to define and arrays within arrays has to go multiple layers in many places, I'll also write some setters and getters and other helpful scripts so I don't need to dig up the details every time. I just call a script and retrieve what I wanted. The big advantage with those are the autocomplete and argument helper in the editor. When written well, it is normally immediately obvious which script I need to use and what parameters I need to fill in.
 

mcdreamer

Member
Thanks everybody for your feedback! It's good to know I'm following the approach of others here.

@kraifpatrik I will check out your scripts - looks like there's a lot of good stuff there! What I like about using enums is that you've got a defined name which gives you a build error if you make a typo. Whilst there's a bit more to set up I thought this benefit might outweigh that for me.

@Catan You might well be right that'd be better off using lists rather than arrays here. I think it'll come down to what I want to do in terms of serialisation later on as your mention.

@NightFrost Yeah, I've been doing the same with getters and setters. Definitely helps keep the rest of the code clean (and might even make porting over to lightweight objects a bit easier - who knows!)
 

Ido-f

Member
@Catan, arrays and enums do have a disadvantage, enum.something could be 20 for example, and if you want an array to hold a value for array[enum.something] you're allocating memory for all 20 entries even if only a few of the entries are needed.
With maps it's 1 memory allocation per entry. Although, as I have been made aware of, maps can be pretty wasteful with memory on their own right.
 
Last edited:
H

Homunculus

Guest
@Catan, arrays and enums do have a disadvantage, enum.something could be 20 for example, and if you want an array to hold a value for array[enum.something] you're allocating memory for all 20 entries even if only a few of the entries are needed.
With maps it's 1 memory allocation per entry.
You assume that the same enum is being used for a purpose other than indexing array entries, in which case you are right, but that’s generally not the case. Still something to consider though.

It is also worth noting that ds_maps preallocate a lot of memory, even an empty ds_map is probably far heavier than an array with a few dozen of values
 
Last edited by a moderator:

FrostyCat

Redemption Seeker
arrays and enums do have a disadvantage, enum.something could be 20 for example, and if you want an array to hold a value for array[enum.something] you're allocating memory for all 20 entries even if only a few of the entries are needed.
This "disadvantage" is a red herring for people who use the pattern properly.

In every case where I use the enum+array pattern, every entry is an essential property, and I have yet to hit 20 in any situation over the past 3 years. I have agency over what properties are stored, unlike object instances. If it chronically overuses memory, it's always down to poor design, and even then it'll take thousands or millions of these arrays to even start making a difference.

With maps it's 1 memory allocation per entry.
You need to read up on how hash tables work before making claims this misguided.

The instant you create a map, you implicitly set up all those hash table buckets. While the exact number varies by implementation, by having one you are guaranteed to have as many "entries" as there are buckets, even if it's blank. Adding entries into it just adds more on top of that basic amount.

The same is not true for an array that has been backwards-initialized or made with array_create(). The number of entries you tell it to have is more or less the actual number of entries it occupies.
 
Top