2D Minecraft-Like Game, Rendering issue.

Hey guys :3

How do I render what’s only on the screen? I can currently only render an array of:

blocks[50][50], any higher and the game begins to lag. I’m guessing because I am looping through all of those tiles every frame and I need to know how to render much more but only what’s on the screen so it doesn’t lag… Any help?

Hi,
you can calculate which map-rectangle collides with the big screen-rectangle and if there is a collision between them, the map-rectangle will be rendered.

I hope this idea helps you :slight_smile:

Java 2d , may god have mercy on your soul.

It is certainly possible to have good performance in relatively simple games in Java2D.
For example, my Zelda clone (wip), which is entirely Java2D.

This is with 256 Octorocks wandering around the entire map, and they all get their ai updated every logic tick.
I keep the entire map in an array of static tile types and only render the tiles in view.

it’s not the logic tick that’s the issue.

It is possible, although not as easy as an ogl solution: http://www.java-gaming.org/topics/renoria-java-mmorpg/30991/msg/287202/view.html#msg287202

I will try this, thank you :slight_smile:

Yes but my question is how did you get to render what was only on screen?

If you’re iterating through your tiles like this:


for(int x = 0; x < width; x++){
   for(int y = 0; y < height; y++){
      // render the tile at x, y
   }
}

That’ll render all the tiles. But like you said, you only want to render some tiles, so change where x and y start and end. Convert the top left corner of the screen to the world coordinates and start there, and then figure out how wide the screen is in tiles (which is as easy as screenWidth / tileWidthInPixels and the same for height).

Hope that gets you started on what to do.

If the “camera” is pointed at tile (cameraX, cameraY), and the screen is say width x height tiles, then you would do something list this:


int xStart = Math.max(0, cameraX - (width / 2));
int xEnd = Math.min(width , cameraX + (width / 2));
int yStart = Math.max(0, cameraY - (height / 2));
int yEnd = Math.min(height, cameraY + (height / 2));
for(int x = xStart; x < xEnd; x++){
   for(int y = yStart; y < yEnd; y++){
      // render the tile at x, y
   }
}

Also, I wonder if the problem is really rendering. How are you doing collision detection? Collision detection can explode depending on how you are doing it. for example, let’s say you have 10 entities all moving, and each frame you simplistically check all the other entities for collision. That’s 100 checks (including checking collision with self :slight_smile: ). If you do the same for 100 entities, you are then doing 10,000 collision checks per frame.

I cant stand using java2D any more, i used to be in the same situation as you, but as soon as i switched over to LWJGL my games now run 1000% faster and a old freerome game i made can be 10,000x times the size of earth (that is if 1 block = 1mx1m) and still run 60 fps…make the change xD

The bottleneck in such a game is always likely to be collision detection. so if you make the world larger but do not increase the number of entities, the game will actually go faster as there is less collision (more correctly, fewer collidables per grid square if you are using a grid-based broad phase collision detection). Would you get 60 FPS if your world included 10,000 x 7 billion people?

If you are culling the view to the visible tiles and there is minimal action happening off-screen , why would the world scale make any difference?

You can’t stand Java2D because it punishes you for the bad code YOU write…? Remarkable ;P. What you meant was you’re able to write unproficient code and take less of a performance hit when using LWJGL.

You can have a game that uses Java2D for rendering and is 10,000x times the size of earth as well, and get 60 FPS… if you’re rendering just what’s on screen, then your world size doesn’t matter.

Of course LWJGL > Java2D, but not for that reason.

I don’t know if this is bad advice, but I think that new (or relatively new) Java programmers should refrain from using libraries because it doesn’t reflect their programming ability at all. When you write things from scratch, you learn how to make efficient and fast code.

Java 2D is actually a really good place to begin to learn before moving on to something else.

This is how I render only what is on screen…

When you create your map, pass it the width and height of your screen to determine how many tiles to render at a time, i.e…

public TileMap(int screenWidth, int screenHeight) {
    rowsToRender = screenHeight / tileSize + 2;
    colsToRender = screenWidth / tileSize + 2;
}

Notice that you add an extra two tiles, this is just a safety buffer so you don’t see tiles appearing and disappearing as you walk. Now say if you are telling your tile map where the player is (the position variable in the below), then you can render only the tiles immediately surrounding the player using a render loop similar to the below.

public void render(Graphics2D g) {
		int rowOffset = -position.intY() % tileSize;
		int colOffset = -position.intX() % tileSize;
		
		String mapString;
		int row, col;

		for (int r = 0; r < rowsToRender; r++) {
			for (int c = 0; c < colsToRender; c++) {
				row = r + position.intY() / tileSize;
				col = c + position.intX() / tileSize;
				
				if (isTileOutOfBounds(row, col))
					break;
				
				// if ((mapString = mapArray[row][col]).equals("NA"))
					continue;
				
				// row = charToInt(mapString.charAt(0));
				// col = charToInt(mapString.charAt(1));
				g.drawImage(tiles[row][col].tile, c * tileSize + colOffset, r * tileSize + rowOffset, null);
			}
		}
	}

In this method, the row and col offset describe how far along the current tile you are on, without this, the player will jump from tile to tile instead of moving smoothly across it, you can see it added to the draw method at the bottom of the loop. The loop will now render the number of rows / cols that we set in the constructor.

The commented-out lines are relevant to how I build and read my maps and will be different for you…

I hope this helps!

consider putting blocks into chunks so one chunk is 64 blocks so that’s a 8x8 chunk

Well this thread is a little old, but anyway.

Chunks aren’t a solution to this problem, you’d only be doing redundant work. We know exactly what tiles needed to be rendered with the use of basic arithmetic, so there’s no need for acceleration algorithms.

Chunks are more beneficial for loading in parts of the map at run time, where we can’t store all the data in memory, and incur I/O costs. Like Minecraft, you could also use it for a procedurally generated world, as it’d perhaps be a strange thing to do to keep rescaling a spartial partitioning structure to the new size of the world, and certainly wouldn’t want to be processing through data that isn’t being used.

I had a similar issue when I wrote my first 2d tile based game. Here’s the solution I came up with:

Separate the map into chunks (like said above) and give each chunk its own image. That chunk will have a flag called ‘update’ which is checked every time the game is drawn. If the chunk is due for an update, the image of that chunk will be recreated and the update flag will turn off.

That way instead of drawing 8x8 tiles through a loop, you’re drawing a single image which is comprised of those 8x8 tiles.

The cons of this approach is if you want tiles your character goes under, then you will need multiple ‘layers’ for each chunk so you can render over the character. Also if you have tiles that change frequently (animated) then it might be considerable to add a system which causes only specific tiles to be redrawn to that chunks image.