[Solved] How do i get a ton of (non animated) sprites into the scene without lag?

Yeah, generating the world is controlled by a Pathfinding object, which spawns more objects with downward force, which place blocks depending on depth, which I have yet to add, so it’s all dirt. As soon as the terrain finishes generating, I get perfect performance again. I don’t know if there is any way to optimize it.

But it does

How did you get procedural generation to work I am also making a 2d Minecraft clone and I can’t figure out how to make platformer procedural genoration

1 Like

I will write a separate thread on how i achieved this, and let you know when i finish it.
On that note, the generation is currently imcomplete, so i may be a few days.

OK thanks I would love that

Sorry, to what is that part of my post is that responding?

So it’s not the number of sprites in the scene, but the algorithm to generate the terrain that’s the issue.

Minecraft but in 2D sounds a lot like Terraria. I’d suggest you research Terraria terrain generation to see how others do it and figure out a way to implement it in GDevelop (here’s a Pygame example using perlin noise)

I linked you my forum post where i was trying to solve FPS lag caused by placing objects on scene

I have written how many objects i was able to place before getting FPS lag depending on how many behaviors said object had

And there are still links to previews so any1 can test how number of sprites on scene affects FPS especially when you add behaviors to them

OP never mentions behaviours. Behaviours and effects will most likely have an impact the game performance.

Here’s a post (albeit from 10 years ago) where thousands of sprites are added to a scene before the games drops to 30 FPS.


However, from @Inusitatus’s more recent post, it looks like the terrain generation is the issue, not the number of sprites on the screen. That was a red herring.

My whole test was about how many objects can be created on scene before FPS lags kicks in while behaviors were just addition
But last instance of my project was a test without any behaviors


Which proves objects do affect performance
I guess it would vary depending on machine specs
For me it was around 7k of 16x16 pixel objects

Thanks for highlighting that part, the original post was too much for me to go through. I ran the gd.games link for test #4.

Firstly, I don’t know how or what you measured FPS. There’s no FPS displayed on the screen, and there’s no mention how much of the scene is displayed on the screen (i.e the zoom factor). So I ran 2 tabs with the behaviour free objects test, one with the initial number of stones, the other with almost 8000 stones.

If I zoomed out equally on both tabs (so all 8000 objects showing in one of the tabs), then there was a noticeable decrease in movement speed. This tab also slowed down the creation of the stones.

However, when zoomed in so the screen height was 11 stones - a zoom factor closer to what OP will be doing as I doubt their game will have the whole world showing - then there appeared no difference to the movement speed. It took the same perceived time to travel a set distance in both tabs.

But the inclusion of a FPS counter on screen would be the best measure. Feel and judgment is subjective unreliable. And some way to accurately measure the movement speed. Something like a start and finish objects that are in line horizontally and measuring the time taken to get from one to the other.

i ran into another issue:

I do not want to measure FPS cause i do not care if game runs at 60 or 50 or 40 FPS
Of course i want it to run at 60 FPS

But my idea to measure it is not with numbers
But in first instance when i feel my game runs slower
When i feel like i am on a moon or in underwater level

And that is what numbers of each test provides
When game started entering SLUG MODE

I still have this project and next to nothing is changed in it since that test
If you want i can zip it and share it here and you can whatever you want with it
If not tell me how to print FPS to text object cause that never worked for me ToString(round(1/TimeDelta())) printed to text object always displays for me 60 FPS in any project even in ones i force lag on purpose

EDIT PART
Forgot to answer your questions
On my ancient PC that remember times of dinosaures all tests were made on same zoom as you have when you launch the game i did not zoom in or out i just spam created new objects

What Silver wrote below is correct i am here mixing 2 things FPS lag (where frame rate is choppy and game slowdown where you feel like time scale of game is lower and you start moving like slug) which is well gamers thing to do but here we are not gamers but devs in the 1st place

So in all my test i mean i start getting SLUG MODE where game feels like you ran underwater level while frame rate for me feels steel smooth
Yet game runs like i decreased time scale on all layers

Some of this needs to be cleared from what I’m reading in the thread.

The original question was how many sprites can be added to the scene without causing lag. And how to add more.

As far as ZeroX4’s test:
I’ve had 30000 sprites in the same scene within the viewable camera viewport while still having full control over a platform character with no impact to fluidity or slowdown. I’ve had another 30000 sprites outside the scene, and there is still no change. As soon as there are more than roughly 42k sprites visible in the scene is when you will start having rendering based slowdown (FPS loss and game slowdown if you have a minimum FPS)

MrMen is correct in his statements. Objects outside the current window/viewport (with no events nor behaviors on them) will not have any tangible impact on game performance until they are within a specific distance of their layer’s camera viewport. The exception to this is sprites if you manually toggle on the “render while off screen” option.

Other things to note:

  • Creating (or deleting) objects is via events is a performance impacting action because it has to modify numerous object lists. Every frame an object is created or deleted will have much more CPU needs than a frame where objects aren’t being created or deleted.
  • Having objects with behaviors (regardless of events or not) has performance impact, because every event within the behavior has to be processed per object in the scene, even if it’s just for evaluating the conditions. Having objects with behaviors that have per-frame actions will start increase the CPU need for each object. On my machine even just having the platform behavior on the objects will make it so I can only have about 12000 objects on screen before it starts dropping framerate.

As a side note: Lag is input or network latency, not framerate. Please don’t use those terms interchangeably as they do not mean the same thing and are generally not considered the same thing in development. This is not specificly at the op, but clarification for anyone who uses the term for anything other than input latency or network latency.

For the original question:

  1. Reduce (or remove) any behaviors on the objects to improve bulk object performance.
  2. If you do have behaviors on the objects, turn them off upon creation and do not turn them back on until after your procedural generation is completed. The same would be true for effects. Turning them off on creation will still have a 1-frame impact, but it will be dramatically less time needed to finish procedural creation with them off.
  3. Make sure none of your events that target the objects run while procedural generation is happening (outside of the events that actually do procedural generation)
  4. Ensure you’re not doing something wild like creating thousands of objects with 500x500 or greater size textures.

Stones have no behaviors
I provide screenshots of how stones are created so there is no doubt they are causing slowdown on their own
I was always printing to text that ToString(round(1/TimeDelta()))
It never changed for me from 60 to anything
Now i set variable to round(1/TimeDelta()) and printed that variable in my other project
And it flickers sometimes from 60 to 59
But in this project it still sticks to 60 even when slowdown hits the fan

https://gd.games/instant-builds/dbd9fc1e-1d18-4dda-a6aa-ccc894fabc1a

Unfortunately it seems like your testing has quite a few things going on beyond just creating the stone. Keep in mind having a “For each (x) object” will still impact performance just from the condition checks if you have a ton of objects. The more instances of (x) you have, the more impactful a For Each event will be.

Here’s an example where 35k objects are created in the first frame.
https://game-previews.gdevelop.io/1701267475390-880491/index.html

When the scene first loads, no objects are created through events. It takes exactly 1 second for the heart to rotate, framerate is 60fps (well, in my case 59.94). If you hit C, the global variable is toggled, and the scene is restarted. 35000 sprites are created. It still takes 1 second for a full rotation of hearts, framerate is 59.94 (after a moment because creating 35000 sprites in a single frame will cause a delay, as mentioend above). There is no slowdown other than the frame where 35000 objects are created in one frame. After creation there is no impact.

Also keep in mind that framerate is always going to depend on your refresh rate as GDevelop is locked at vsynch, and most 60hz displays aren’t actually 60hz, but 59.94 or 59.97 (same is true for higher refresh rates, 120 hz displays are usually 119.88 or 119.92, etc). So a maximum 60 fps game will have some instances where it is not locked at 60.

1 Like

Just as a programming tip/note, that Repeat for each instance of Stone event is unnecessary :

The Selector is in collision with Stone is enough to just get the stone that’s under the selector object. You don’t need to iterate over every stone object to check for the collision between it and the selector object. The collision event effectively does that for you.

In my game, once a tile is created, I give it an unique object ID variable, and I also save its informations in a global variable in this format:

Structure.TileX.TileY.ID

When I need to know if the cursor is over an tile, I do

Conditions:

Child ToString(floor(CursorX() / 16)) exists in global variable Structure

Child ToString(floor(CursorY() / 16)) exists in global variable Structure[ToString(floor(CursorX() / 16)]

Tile variable ID is equal to Structure[ToString(floor(CursorX() / 16))][ToString(floor(CursorY() / 16))].ID

In that way, I manage to know if the cursor is hovering a tile just by checking a single parameter (the tile ID match with global variable.)

It was for something else it’s leftover
I did not care for cleaning it up

I was wondering if pick all instances would be better solution
But at this point i do not have heart to invest in this project for now
I gonna test it later