Culling drawing tiles in a 2D map

I could've sworn there was a more elegant way to cull off tiles with just For loops.

I have a tilemap of 128x128, but I only want to render the tile that the player is on, and -8/+8 in all directions, so that's a 17x17 tile area I want to render, and the ones outside that are skipped over.

I'm pretty sure I'm supposed to use the two For loops here - outer For loop for rows, inner For loop for cols.

1
2
3
4
5
6
7
for(int r = r_min; r < r_max+1; ++r)
{
  for(int c = c_min; c < c_max+1; ++c)
  {
    DrawTile(c - pos_x + cam_offset_x, r - pos_y + cam_offset_y);
  }
}


So I check -8 and +8 tiles from where my centered object is (represented here by pos_x/pos_y - usually the Player), and make my r_min/r_max, c_min/c_max based on that. If I leave it at that, I'll be rendering out of bounds when near the edges of the map, so I need to ... clamp those ... with If checks?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int r_min = pos_y - 8;
if(r_min < 0) r_min = 0;

int r_max = pos_y + 8;
if(r_max > MAX_MAP_SIZE - 1) r_max = MAX_MAP_SIZE - 1;

int c_min = pos_x - 8;
if(c_min < 0) c_min = 0;

int c_max = pos_x + 8;
if(c_max > MAX_MAP_SIZE - 1) c_max = MAX_MAP_SIZE - 1;

// And then the loops right after
for(int r = r_min; r < r_max+1; ++r)
{
  for(int c = c_min; c < c_max+1; ++c)
  {
    DrawTile(c - pos_x + cam_offset_x, r - pos_y + cam_offset_y);
  }
}


Yeah... I swear there was a nicer way that didn't use If checks like this, or is this definitely the cleanest way of doing this? I really could've sworn that there was a less clunky way to accomplish this. Thank you.
Last edited on
Could you do something like this instead?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int bound(num, min, max) {
  if (num < min) return min;
  if (num > max) return max;
  return num;
}

int drawDisplay(centerX, centerY, displaySize, mapSize) {
  int minY = bound(yPos - displaySize, 0, mapSize - displaySize);
  int minX = bound(xPos - displaySize, 0, mapSize - displaySize);
  int maxY = bound(yPos + displaySize, displaySize, mapSize);
  int maxX = bound(xPos + displaySize, displaySize, mapSize);

  for(int x = minX; x <= maxX; x++)
    for(int y = minY; y <= maxY; y++)
      DrawTile(x, y);
}


This assumes DrawTile is a global function, and that you pass in your camera position (it seems goofy to me that you wouldn't account for that in your boundary checking)
Last edited on
That's definitely a more sane way of doing it, thanks, but I could've sworn there was some "optimization" of doing this without the conditionals? Somehow I felt that because of how For loops work to begin with, that there's an intrinsic culling method... But I'm willing to admit I'm wrong and that conditionals are absolutely necessary.

Any thoughts?

(FYI... For anyone wondering, cpu speed isn't my concern here, I'm just trying to brush up on good/clever programming since I'm rusty (and relatively new to most people here anyways))
you can definitely do it all in your for loop, but it makes it less easy to understand. If you want something in particular to happen as a result of a set of circumstances it is a bit difficult to avoid a conditional statement ^_^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

int DrawTile(int x, int y){std::cout << x << ", " << y << "\n";return 0;}

int main() {
    
    int displayWidth = 100;
    int displayHeight = 100;
    
    int posX = 50;
    int posY = 95;
    
    for (int x = posX - 10 < 0 ? 0 : posX - 10; x <= posX + 10 && x < displayWidth; x++){
        for(int y = posY - 10 < 0 ? 0 : posY - 10; y <= posY + 10 && y < displayHeight; y++) {
            DrawTile(x,y);
        }
    }
    
}
Yup, ternary, haha, still a conditional of course but yeah you've convinced me now, that a conditional is necessary. I feel like I did it with modulus+overflow or something similarly weird in the past, but when I think about it, I guess the for loop would fail entirely when the overflow happens, so I'm probably just remembering wrong.

Even so, I suppose I would prefer clearer code (like your example in the 2nd post). Thanks for the posts/advice, appreciated.
Last edited on
Topic archived. No new replies allowed.