Help with code for displaying tiles to screen


(Kea Oliver) #1

I have some code here that I thought was working well to write a map of tiles to the screen. However when i tested by writing a bit so that it would be a blank spot on the map when I move the map around the blank spot moves too, when it should be at a fixed location on the map itself.

Should have the two files that are needed here.


(Pharap) #2

I’m not sure what it was doing before but this will fix it:

void drawworld()
{
	setMapBit(8,8);
	setMapBit(7,7);
	
	const int tileswide = 96 / TILE_SIZE + 1;
	const int tilestall = 64 / TILE_SIZE + 1;
	
	for(int y = 0; y < tilestall; ++y)
	{
		for(int x = 0; x < tileswide; ++x)
		{
			const int tilex = mapx + (x * TILE_SIZE);
			const int tiley = mapy + (y * TILE_SIZE);

			if(getMapBit(x, y))
				sprites.drawSelfMasked(tilex, tiley, longtileset, 0 );
			else 
				sprites.drawSelfMasked(tilex, tiley, longtileset, 1 );
		}
	}
	
	arduboy.fillRect(0, 0, 48, 8, BLACK);
	arduboy.setCursor(0, 0);
	arduboy.print(0 - mapx / TILE_SIZE);
	arduboy.print(",");
	arduboy.print(0 - mapy / TILE_SIZE);
}

I saw that you were trying to clip the map somehow (presumably trying to only draw what’s on screen) but I’ve just cut that out for now.

(If you only want to draw what’s on screen, there is a better way,
but I’m about to head off so I’ll have to explain it later.)


(Kea Oliver) #3

Hey, yeah I dont want to draw the entire map because its 64x64 tiles so Im planning on only drawing part of it. Will keep an eye out for your explanation if/when you get the time!


(Pharap) #4

So basically, instead of looping through all the tiles and then deciding whether or not to draw them,
you should be able to figure out the range of tiles that are actually on screen and then only loop through the tiles that you actually need to draw.

I’m currently figuring out the calculations needed to do it.


(Pharap) #5

I have figured out a way to do it, but naturally it uses more progmem space.

void drawworld()
{	
	constexpr int screenWidthInTiles = (WIDTH / TILE_SIZE);
	constexpr int screenHeightInTiles = (HEIGHT / TILE_SIZE);
	
	setMapBit(8,8);
	setMapBit(7,7);
	
	const int tempFirstX = (-mapx / TILE_SIZE);
	const int tempFirstY = (-mapy / TILE_SIZE);
	const int tempLastX = (tempFirstX + screenWidthInTiles);
	const int tempLastY = (tempFirstY + screenHeightInTiles);

	const int firstX = (tempFirstX >= 0) ? tempFirstX : 0;
	const int firstY = (tempFirstY >= 0) ? tempFirstY : 0;
	const int lastX = (tempLastX <= screenWidthInTiles) ? tempLastX : screenWidthInTiles;
	const int lastY = (tempLastY <= screenHeightInTiles) ? tempLastY : screenHeightInTiles;
	
	for(int y = firstY; y < lastY; ++y)
	{
		for(int x = firstX; x < lastX; ++x)
		{		
			const int drawX = mapx + (x * TILE_SIZE);
			const int drawY = mapy + (y * TILE_SIZE);

			const uint8_t tileIndex = (getMapBit(x, y) != 0) ? 0 : 1;
			Sprites::drawSelfMasked(drawX, drawY, longtileset, tileIndex);
		}
	}
}

I made a few other changes while I was at it, to make the code simpler.

This could probably be improved further,
but I don’t want to change it too much in case my changes start getting confusing.


(Kea Oliver) #6

This is pretty great, doesnt seem to draw more of the map as i move around but I can work on that, thanks for the help!


(Pharap) #7

Oh right, I realise what I’ve done wrong.
I accidentally limited it to drawing the first screen’s worth of tiles instead of the whole map.

Here’s a fixed version:

void drawworld()
{	
	constexpr int screenWidthInTiles = (WIDTH / TILE_SIZE);
	constexpr int screenHeightInTiles = (HEIGHT / TILE_SIZE);
	
	setMapBit(8,8);
	setMapBit(7,7);
	
	const int tempFirstX = (-mapx / TILE_SIZE);
	const int tempFirstY = (-mapy / TILE_SIZE);
	const int tempLastX = ((tempFirstX + screenWidthInTiles) + 1);
	const int tempLastY = ((tempFirstY + screenHeightInTiles) + 1);

	const int firstX = (tempFirstX >= 0) ? tempFirstX : 0;
	const int firstY = (tempFirstY >= 0) ? tempFirstY : 0;
	const int lastX = (tempLastX < MAP_X) ? tempLastX : MAP_X;
	const int lastY = (tempLastY < MAP_Y) ? tempLastY : MAP_Y;
	
	for(int y = firstY; y < lastY; ++y)
	{
		for(int x = firstX; x < lastX; ++x)
		{		
			const int drawX = mapx + (x * TILE_SIZE);
			const int drawY = mapy + (y * TILE_SIZE);

			const uint8_t tileIndex = (getMapBit(x, y) != 0) ? 0 : 1;
			Sprites::drawSelfMasked(drawX, drawY, longtileset, tileIndex);
		}
	}
}

The + 1 for tempLastX and tempLastY is important,
because the loops are checking with < instead of <=.


By the way, I highly recommend using constexpr variables instead of macros.
constexpr variables are much more likely to be evaluated at compile time, and give better error messages.
(They also look a bit tidier.)


(Kea Oliver) #8

I actually fixed it myself but I will look over your code which im sure is far more efficient and see what i can learn. Thankyou!