I am makng a 2d minecraft clone, with procedural terrain.
I want to have a decent sized world, which involves a ton of sprites.
I tried hiding all blocks outside a certain radius, but it did not improve the performance.
What is the expected result
It should be lass laggy.
What is the actual result
after some of the world generates, i get maybe 1 fps or something.
(Deletion of off-screen blocks will be handled at part 2)
In order to recreate the blocks when they should be on screen, save the information of every block in a structure inside a scene array variable (specifically X and Y position, and also a boolean)
You should give each block an unique ID variable once created.
The scene array variable should look like this (you wont create it manually, but through events):
And loop through it using the event (not action or condition) “For every child of structure or array variable”
Assuming you know the basics of that event, create a temp scene variable that will store the current child and another for the child name.
Then use conditions
“If variable Child.IsOccupied is false”
“If variable Child.x > CameraBorderLeft()”
“If variable Child.x < CameraBorderRight()”
“If variable Child.y > CameraBorderTop()”
“If variable Child.y < CameraBorderBottom()”
Change the variable ArrayStoringEveryBlock[ChildName].IsOccupied set to true
Create Block at Child.x;Child.y
Deletion of blocks when they are not on screen:
Use the conditions:
Or: (this is the name of the condition)
“Block X position < CameraBorderLeft()”
“Block X position > CameraBorderRight()”
“Block Y position > CameraBorderTop()”
“Block Y position < CameraBorderBottom()”
Change the variable ArrayStoringEveryBlock[Block.ID].IsOccupied set to false
(You may need to implement something such as “- 16 or + 16” at the end of the camera expressions depending of the block size)
I think this is everything, if I miss anything tell me.
(Edit: If you really want performance, you will really have to delete the off-screen blocks instead of hiding them)
I ended up waiting until the world gen was done, and ended up with very little lag, if any.
If I ever need to optimize my scene, i will always have this thread to refer to, so thanks you so much for your input!
The number of sprites in a scene shouldn’t have that such an impact that it reduces the game to 1 fps. Sprites not on the rendered part of the scene are not drawn. Deleting and recreating sprites would consume more processing time than just leaving them in the scene for GDevelop to handle.
If you are getting 1 fps, I’d put my money on it being caused by events. The most common suspect is any Repeat for each instance of <some_world_block>, which really like to contribute to game lag.
o figure out where the lag is happening, I suggest you sections of events under an event group. Then debug, and run the profiler. This will point to where the bottle neck is occurring.
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.
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)
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 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
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:
Reduce (or remove) any behaviors on the objects to improve bulk object performance.
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.
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)
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
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.
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.