I'm doing a picross game and stumble about a serious performance issue. As any picross fan know you quickly end up with a LOT of case to manage (a 40x40 grid is 1600 case ...)

I tried two solution : one 2Dnode per case (easier to manage input and easier to check for bug since i got separate .gd for the main process and the update case one) and using a single script (lot of computing position involved but perhaps better performance)

in both case FPS drop to 16 or so when the grid reach size like 30x30

To make sure my code wasn't the issue i put all but the grid initialization and the _draw process as comment (setting size through a variable manually set in editor) and got the same result. i double check for no update call hidden somewhere.

Does it means a 30x30 2DArray is too much for the engine to manage ? If so is there a better way to do this ?

I use $"Label".set_text(String(int(Engine.get_frames_per_second()))) to check FPS. perhaps it's not the good way ?

As a side note i use \ a lot (those corrd check can have long if condition ...) but when i comment using """ it give me error about misplaced \ I just have to remove them but when using commenting to temporarily disable part of code it's annoying as hell ... is there a solution ?

  • Make sure to use Godot 3.2.2 and the GLES2 renderer so you can benefit from 2D batching, which will give you a significant speedup in most cases.
  • Consider using a TileMap instead of an array of 2D nodes.
  • You don't need to store a 2D array as a 2D array if you know its width (or height) in advance. Instead, you can store it as an 1D array and loop over it as an 1D array. This is a common optimization in programming.

As a side note i use \ a lot (those corrd check can have long if condition ...) but when i comment using """ it give me error about misplaced \ I just have to remove them but when using commenting to temporarily disable part of code it's annoying as hell ... is there a solution ?

You can wrap multi-line conditions in parentheses instead of using backslashes:

if (
    2 == 4 and
    4 <= 6 and
    6 < 8
):
    print("yes")

Make sure to use Godot 3.2.2 and the GLES2 renderer so you can benefit from 2D batching, which will give you a significant speedup in most cases.<

No change

Consider using a TileMap instead of an array of 2D nodes.<

Going to try it

You don't need to store a 2D array as a 2D array if you know its width (or height) in advance. Instead, you can store it as an 1D array and loop over it as an 1D array. This is a common optimization in programming.<

I don't get this part. in the case of a 40x40 grid i would have to create 40 1D Array ? or, since the stat is either 0,1 or 2 storing a 40 number long string/int and browse it ? Speaking of the 40 1D array, is there a way to create (and check) variable using a string as name ? like i create string "Line40Row10" and use something like var(string) = or whatever. Or, in this case, i should use Array referenced by string (can't rememebr the right name ...)

Consider using a TileMap instead of an array of 2D nodes.<

it works nice but no change in perf ... for tehmoment that is i still have to clean the current code and get rid of obsolete part

Something i was wondering. We need to use update() to change the display but does it means the actual display is saved as is or is it recomputed anyway ? could explain the perf issue since it would means each rectangle would be redrawn.

Since case have dynamic size (based on current grid size) i can't just use tile as is but i guess there's some method to resize them . I do'nt really like it since i won't have as much control as i liked over the result but does resizing a batch of sprite take less ressource than drawing x rectangle ? seems a bit counterintuitive but could be a solution.

Ok so using a tilemap solved the issue. I stil get under 40 fps when i got lot of case crossed (i had to draw the cross using draw_line, resizing a tile was just ugly) but it only happen when there is like 1K of them (which is not as rare as one might think ...) stil way better than before (i had like 8 fps ...) and not a gameplay issue Thansk a lot

PS : even if the 2D array wasn't the issue in the end it would still be nice to explain me the looping inside 1D array to make it 2D. I do'nt really get it.

PS2 : it seems rectangle and line are indeed recomputed even when update() is not called. did you consider storing the result of a draw sequence as an image so it doesn't have to be redraw from scratch ?

PS2 : it seems rectangle and line are indeed recomputed even when update() is not called. did you consider storing the result of a draw sequence as an image so it doesn't have to be redraw from scratch ?

You can do this yourself by drawing inside a Viewport with the update mode set to "Once".

Cool I was a bit surprised it wasn't already the case. it'll improve performance even more :) Thanks for the info

Cool I was a bit surprised it wasn't already the case.

Immediate-mode drawing requires you to draw every frame. It's more suited to things that can change every frame than things that only need to be drawn once and then let as-is.

2 years later