Advertisement

Need help

Started by August 09, 2000 03:03 PM
2 comments, last by JSCFaith 24 years, 4 months ago
Hey, Ok, this has been a problem for a long time, I have a funtino for blting a isometric map, but it is way to slow, I know why its slow I just dont know how to fix it. The reason it is slow, is becuase I loop threw the whole map every time the funtion is run, I need to find a way to loop only threw the tiles on the screen, I know how to do this with basic tile maps, but not with isometric maps, here is my funtion, if anyone can tell me how to make it so I only loop threw the tiles on the screen I would like that.
            
for (int y = 0; y < WORLD_SIZEY; y++) // How can I make this so I only loop threw the tiles on the screen? 


  {
	 
    for (int x = 0; x < WORLD_SIZEX; x++, bob++)
    {
		
      timelooped++;
	

	  var1 = (y * -32) + ((x - WorldPosx) * 32);
	  var2 = ((y - WorldPosy) << 4) + (x << 4);

	  
	  
	  tile_dest.left = var1;
	  tile_dest.right = var1 + TILE_WIDTH;
	  tile_dest.top = var2;
	  tile_dest.bottom = var2 + TILE_HEIGHT;
	  
	  
	  if((tile_dest.left < (SCREEN_WIDTH)) && (tile_dest.left > -40) && (tile_dest.top < (SCREEN_HEIGHT - 170)) && (tile_dest.top > -50)) {
	    
	  tile = map[x][y].tileID;    // tile now stores the ID of this particular tile and the Rect of the tile

	  

	  ddrval = lpDDSBack->Blt(&tile_dest, tilebmp, &tile_src, DDBLT_WAIT | DDBLT_KEYSRC , NULL);
  
	 
	  map[x][y].tileposx = tile_dest.left;
	  map[x][y].tileposy = tile_dest.top + 41;
	  
	  
	  tilesblt++;


	  
	  if(ddrval != DD_OK) {
		  MessageBox(main_window_handle, "Error: Couldn''t draw the map.", "Error", MB_OK);
		  PostQuitMessage(0);
	  }
	

	  
	  }
  
	}
	
	


  }
  return(timelooped);
} 

            
If someone could help me I would like that. Thanks, James
Can someone please help me?
Advertisement
Okay, it''s been a while since I''ve done any iso coding, but here''s how I seem to remember doing it. This is just off the top of my head, I may have inadvertently reversed some signs or some comparisons or something like that. Or just muffed it completely. I''m sure I''ll be corrected if so .

Using the formula:

tileX = (screenY / tileHeight) + (screenX / tileWidth);
tileY = (screenY / tileHeight) - (screenX / tileWidth);

you can transform from screen-space to tile-space (assuming your screen co-ordinates are relative to the tile origin, or you at least account for this at some point).

So let''s say the player is at playerX, playerY (these are floating point values, along with most every other variable I''ll use here). You want this to be at the centre of the screen. So first you calculate the tile co-ordinates at the origin of the screen:

originX = playerX - adjustmentValueX;
originY = playerY - adjustmentValueY;

What are the adjustment values? They''re the difference between the centre and the origin of your screen, in tile-space (ie. the number of tiles across, and down, to get from the upper-left corner of the screen to the centre).

These need only be calculated once for a given screen dimension, and can be calculated using the screen-to-tile space tranform formula:

adjustmentValueX = (screenHeight * 0.5) / tileHeight + (screenWidth * 0.5) / tileWidth;
adjustmentValueY = (screenHeight * 0.5) / tileHeight - (screenWidth * 0.5) / tileWidth;


Okay, now we have the exact (assuming you use floats for the above variables) tile co-ordinates of the screen origin in originX, originY. Obviously the decimal part of these will be the tile to draw (ie. map[floor(originX)][floor(originY)] or however you access your map). And the fractional part indicates which part of the tile should be aligned with the screen origin. So the screen co-ords you draw the tile at are:

( - fract(originX) * tileWidth, - fract(originY) * tileHeight );

I used fract() to indicate the fractional part of the number (ie. fract(x) = x - floor(x) ).

That also assumes that if draw a tile a (x,y) then the top of the tile''s diamond will be at y, and the left most point of the tile''s diamond will be at x. So adjust to suit your own tile-drawing routine[1].

Okay, so we''ve worked out the first tile to draw, and its screen co-ordinates! Now we just draw n more tiles along the top of the screen, where n is the number of tiles required to fill the top of the screen. This value is simply the screen width divided by the tile width. You also need the number of rows to draw DOWN the screen. This value is the screen height divided by HALF the tile height. "Half" because of the way the tiles interlock. So:

tilesPerRow = screenWidth / tileWidth;
rowsPerScreen = 2 * screenHeight / tileHeight;

.<br><br>Although we know we only need to draw n tiles per row, the fact of the matter is we need to know how to offset every second row (relative to the first tile). That is, when we draw the second row, is the first tile to the left or to the right of the first row''s first tile. The answer is simple: If you can see ANY of the left half of the first tile, the next row is offset by -halfTileWidth, otherwise it''s offset by +halfTileWidth. We can use the fractional parts of originX and originY to calculate this:<br><br>offsetValue = (fract(originX) >= fract(originY)) ? +(tileWidth * 0.5) : -(tileWidth * 0.5);<br><br>Now we don''t really need to calculate an offset for Y axis because we''re drawing left to right. But it does cause one more head-ache: What if the tile at the origin has its topmost point at y = 0? Or y = -12? Or -w, where w < (tileHeight * 0.5)? This would mean that the tile at (originX, originY-1) would be partially visible. But we draw DOWN the tile-map, so we''d never draw it. The problem is solved by adjusting our starting row thusly, if required:<br><br>[breaking into some sorta psuedo-code here].<br><br>[ (screenX, screenY) are the co-ordinates of the first tile].<br><br>IF screenY > -(tileHeight * 0.5) THEN<br> screenY = screenY - (tileHeight * 0.5);<br> screenX = screenX + offsetValue;<br> offsetValue = -offsetValue;<br>ENDIF<br><br><br>Basically, you can now render all the tiles required in a couple of simple for() loops. Every second row (ie. if (rowCounter & 1) == 1), the tiles are drawn with an X offset of offsetValue. Because you''re drawing a row of tiles as it appears on the screen, you have to increment tileX and tileY after drawing each tile.<br><br>The other tricky part is the start tile for each row. Basically the start tile for the rows alternates between being the current start tile + 1 along the tile''s x-axis, and the current start tile + 1 along the tile''s y-axis. If (offsetValue >= 0) then, the start tile for the second row will be (tileX + 1, tileY), and for the third: (tileX + 1, tileY + 1), and so on. <br><br>If (offsetValue < 0), then it goes (tileX, tileY + 1), (tileX + 1, tileY + 1), etc….<br><br>And yeah, it''s pretty fast (well, you only process the tiles that are at least partially on screen). So the size of the map doesn''t affect the drawing time at all. <br><br>And another bonus is that you know that only the first two and the last two rows could be partially off-screen. And the first and the last tile of each row could also be partially off-screen. All the rest are always on screen (so no worries about clipping).<br><br> If I can find your e-mail address (is that possible on GameDev.net? I don''t know…) I''ll e-mail you my (old) drawing code. It looks much simpler in code <img src="smile.gif" width=15 height=15 align=middle>.<br><br>Hope that helps a bit!<br><br>-Hotstone<br><br>[1] I just looked down at your code and yeah, I don''t think you need to adjust anything.
Yeah its possible to find out what someone e-mail address is on GameDev. Thanks for the help, I will try it out, and here is my E-mail if you want to send your old code, (i would like that).

Thanks,


JSCFaith@hotmail.com is my e-mail address, cya later

This topic is closed to new replies.

Advertisement