Question on how to use Game Maker features for more than ten thousand objects

Jihl

Member
Hey there!

My question goes around how to manipulate this many "objects" inside a game.
For what I have been developing so far, I have 4 years of GML develop experience and found myself trying to do this with simple objects at first, but obviously failed. So I'd like to ask anyone who knows; first, is it even possible to handle that many objects with data structures or structs? If it is possible, how can you achieve it?

For this game I need these objects to have alarms, draw events, step events; which I am executing those events inside an "oEntityManager" object. This object will create and go into each struct to execute its events, based on its variables

Now to keep going on this research, I have been looking up on efficiency threads around data structures, like these ones.
Comparing array list and map performance
Performance testing including structs
Using objects like structs

But so far, I can't yet get to the best answer on how to handle this many objects inside a game.
Any ideas?

Thank you very much!
 

Jihl

Member
I'd like to create an ecosystem in which these objects will move, eat eachother, breed, do pathfinding, create other objects and interact in many ways.

I have been testing doing structs as objects, storing them in a ds_list and then going through this list to do their behaviours.
Right now I am 60 FPS with a i7 Intel, 16GB RAM and a Geforce GT 730 (outdated GPU)
All these lines of code are manipulated by one object

------- DRAW EVENT -------

GML:
var lsize = ds_list_size(lifeforms_list);
for (var i = 0; i < lsize; i++)
{
    var object = lifeforms_list[| i];
    with (object)
    {
        draw_set_alpha(image_alpha);
        draw_circle(x, y, 1, false);
        draw_set_alpha(1);
    }
}

-------- STEP EVENT -------
GML:
var lsize = ds_list_size(lifeforms_list);
for (var i = 0; i < lsize; i++)
{
    var object = lifeforms_list[| i];
 
    with (object)
    {
        if (alpha_alarm >= 0)
        {
            alpha_alarm--;
            image_alpha += 0.02;
        }
        else if (alpha_alarm == -1)
        {
            image_alpha -= 0.01;
            // If got to transparency, set alarm again
            if (image_alpha <= 0) {
                alpha_alarm = irandom_range(alpha_alarm_min, alpha_alarm_max); }
        }
    }
}

I am doing this image_alpha test just to test efficiency and how many objects I can handle at the same time.
Later on I will need these objects to have lots of alarms and step event behaviours

I also tried to deposit the structs in a map, but the fps dropped like hell, I will also test with arrays to see how it goes
 
Last edited:

vdweller

Member
Looks like C++ and a simple graphics API might be closer to what you want, also take a look at data oriented design since it offers potentially better performance. I wouldn't go anywhere near such a project with GM.
 
The fundamental limit of performance in GML (as far as I know) is to use arrays to define your objects. I've experimented with this concept for particles here: https://forum.yoyogames.com/index.p...particles-and-other-object-experiments.44288/

I only have a little bit of C++ experience, but from what I gather, objects in big-boi languages are really just arrays. When you make a class, it's variables are just offsets from the class's location in memory.
Using arrays is as close as you can possibly get to that.

It's also worth mentioning that you should save the array in a var before working with it. For some reason using vars is much faster than just directly using the array, and this applies to regular variables too.
And when setting array values, use @ to access the original array, instead of making a copy of it.
GML:
// "things" is a big array of data
var t = things;

t[4][@Things.speed] = 3;
t[4][@Things.direction] = 240;
Here we are altering the 5th instance of "things".

It helps to use enums as the array indices otherwise you'll have no idea what your accessing.

I also suspect you'd run into bottlenecks from drawing before anything else. You might have to write a lot of custom vertex buffery things instead of using draw_sprite's
 

vdweller

Member
The problem (or, perhaps, "necessary evil") with GM is that a value defined by a var is internally a struct (YYRValue) with overloaded operators(?). I haven't seen its implementation, but it's reasonable to assume that when all arithmetic/memory accesses have to do with a compound data type as opposed to fundamental types, things will not be as performant and cache friendly. You may think you just created an array of some number type, but GM just created an array of structs, bloated with who knows what other data. In addition, there are many more conversions which may hurt performance, for instance, indexing an array internally casts your index to an int. For these and many more reasons, and because there are many layers of intermediate code between what you write and what is run, one shouldn't think that just because YYC advertises "speed with the power of C++!!!!", any computationally intensive game is approachable and efficient with GM.
 
Top