I need help optimizing my Draw(); function to draw only what is visible in the viewport. Currently I'm drawing the whole Map array in a diamond shape. How can I make my function store only what is visible?

Here is an image explaining it better: enter image description here Black tiles are X axis, White tiles Y axis. Green tiles are what I would like the function to store, and the Orange rectangle is the viewport.

I'll include the relevant part of my code aswell:

for(i=0;i<Map.length;i++) {
for (j=0;j<Map[i].length;j++) {
tileX = (i - j) * (tile.width / 2);
tileX += (canvas.width /* 2*/) - (tile.width / 2);
tileY = (i + j) * (tile.height / 2);
tileY -= (canvas.height /* 2*/);

    c.drawImage(tile, tileX, tileY);

I've been trying to figure out how to solve this, but since I'm no genius I can't. Help appreciated.

  • 2
    \$\begingroup\$ I answered a similar question gamedev.stackexchange.com/questions/25896/… \$\endgroup\$
    – Jimmy
    Jul 15, 2012 at 1:01
  • \$\begingroup\$ Looks like it's exactly what I need, in your example you use 20 and -8, how did you come up with these numbers? How could I calculate which numbers I would use, my viewport is 640x320, with 64x32 tiles. In the real script these would be dynamic right? \$\endgroup\$ Jul 15, 2012 at 1:24
  • 1
    \$\begingroup\$ keep track of how many columns and rows you can display on your screen. my example uses 20 and -8 because that was what was shown in the other question's picture. For example, if you're starting view is centered on tile (100,100), then you are centered around (X+Y=200), (X-Y=0). Assuming you can display 10 rows and 10 columns (then add 1 to each edge for the half-tiles) then you can display, say, 195 <= x+y <= 205, -5 <= x-y <= 5 \$\endgroup\$
    – Jimmy
    Jul 15, 2012 at 5:19
  • \$\begingroup\$ I've been trying to reverse engineer this for over an hour, and your high numbers are confusing me. Could you explain it with a 5x5 grid. Center is 2,2 left corner 3,1 right corner 1,1, bottom left 3,3 bottom right 1,3. When I do it my function skips every second tile. \$\endgroup\$ Jul 15, 2012 at 5:24
  • \$\begingroup\$ @Jimmy I still can't figure this out even if it would save my life, I made a fiddle of what I've got sofar, please help me figure it out. The green tiles are the one i wish to draw: jsfiddle.net/hustlerinc/QMrrh \$\endgroup\$ Jul 16, 2012 at 3:22

2 Answers 2


(migrated from comments) This is kind of a duplicate of a previous answer I gave to How do I find which isometric tiles are inside the camera's current View.

The way I handle this is by iterating over horizontal/vertical rows and columns. I'll call these axes A/B instead of X/Y (which you're already using for the diagonal axes in your isometric view).

Translating X,Y to A,B is as simple as A = X+Y, B = X-Y. The reverse transformation is X = (A+B)/2, Y = (A-B)/2. If you choose a rectangle such that min<A<max, and min'<b<max', then it corresponds to a particular rectangular viewpoint.

Here is the jsfiddle: http://jsfiddle.net/kAFVB/3/

Here are a couple examples of how different choices of A and B change the dimensions of the viewable area (the shaded rectangle is the same rectangle in both pictures)

enter image description here


This may not be the optimal solution, but a simple optimization would be just to figure out the span of X and Y values and draw everything in between that range.

As in, find the max and min for X and Y in your orange area, and then draw the space if it's X and Y are within the area.

If drawing areas not in your viewport is not an issue, than this should work fine. You may want to increase the max/min boundaries by one [tile size], depending on how you determine the X/Y of you tiles.

The shaded area is the area drawn. The shaded area is the area drawn.

Edit: A slightly more complicated (and computationally heavy) method would be to useout the distance from the center of your viewport to the location you want to draw it [tileX,tileY]. If your viewport's ratio is fixed to what it is now, you could just check if it's within 3 tile widths and 3 tile heights lengths (so if abs(tileX-viewportCenter.X )/tile.width <=3 and abs(tileY-viewportCenter.Y)/tile.height <=3), then draw).

If it isn't fixed, you can figure out the distance from the center to a corner (or use the diagonal distance of the viewport and divide by 2). Then check each tile location's distance the the middle of the screen. This will draw all the required tiles, plus a few extra on the sides (making a circular shape).

  • \$\begingroup\$ The example with the big diamond might actually have to do, since it seems like the easiest solution without being to heavy for the user. But I'd like this to run on smartphones, so I would need to optimize as much as possible. What I've come up with is iterate through the map and start drawing X+1 and Y-1 for each row. But how could I calculate how many tiles to draw for each row? I'll add that to the original post. \$\endgroup\$ Jul 15, 2012 at 1:06
  • 1
    \$\begingroup\$ If you can figure out the x-row and y-row range in tiles (or in pixels/tilesize), you can just add two (tiles). So in the screenshot provided, you know the X and Y distance is ten tiles. So loop through each tile, and if it's X is between (inclusive) the minX-1 and maxX+1, and same for Y, then draw it. \$\endgroup\$
    – Sprunth
    Jul 15, 2012 at 23:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .