YoYoGames / GameMaker-Bugs

Public tracking for GameMaker bugs
21 stars 8 forks source link

A simple new function: tilemap_set_region() #3011

Open jarrrodnb opened 1 year ago

jarrrodnb commented 1 year ago

Is your feature request related to a problem?

I work on a game that uses many large tilemaps layered together.

In game, tilemaps are frequently edited by players at runtime with in-game dragging/drawing tools (designating zones/areas etc. think Rimworld/Prison Architect).

I have of course created my own tilemap_set_region using tilemap_set inside nested for loops, however my issue comes down to performance.

Say, a player wants to clear a 50x50 area from a tilemap. That requires 2500 tilemap_set calls. Then considering players can edit multiple tilemaps at once, removing a 50x50 area of a tilemap across 4 tilemaps results in 10,000 tilemap_set calls at once.

However with an official tilemap_set_region those 10,000 function calls could be reduced to just 4.

Describe the solution you'd like

The addition of a new function: tilemap_set_region( tilemap, tiledata, cellX1, cellY1, cellX2, cellY2);

Describe alternatives you've considered

No response

Additional context

No response

Gamer-XP commented 1 year ago

If we're talking about performance, can also make a function to copy/paste existing region.

Though, I'm not sure if it's THAT big of an issue as long as you use YYC. With VM - yep, loops are super slow.

gnysek commented 1 year ago

Internally it would still execute same function, difference is that for loop could be performed in-engine on VM... so described issue shouldn't harm YYC or NewRuntime, and would only add few frames of performance to VM.

If there's a lag caused by such big tileset (re)placing, I would just execute replacing tiles it in few frames. It's not that hard, for example, placing 100 tiles per frame:

/// create
var rows = 50;
var cols = 50;
total = rows * cols
progress = 0;

// step
for(var i = 0; i < 100; i++) {
var row = progress div rows;
var col = progress % cols;
tilemap_set(..., ..., col, row);
progress++;
if (progress > total) {
    instance_destroy(); break;
}
}