Level movement with Tile array?

Hello!

The plan is to have a scrolling level that as most of them, gives the illusion of the player moving, but it is in fact the level moving. The current issue is that the background/player move around but no new parts of the map show (as seen in the gyfcat).

Here is the Camera and Level class:
https://gist.github.com/AndreasElia/721e3e7a964c140b2387

Here is a gyfcat of what it currently does:

Here is the Level render method (the main part I believe?):


	public void render(Graphics g, Camera camera) {
		for (int y = (int) ((camera.getY() / Level.tileSize) - 2); y < ((camera.getY() + Main.getHei()) / Level.tileSize) + 2; y++) {
			for (int x = (int) ((camera.getX() / Level.tileSize) - 2); x < ((camera.getX() + Main.getWid()) / Level.tileSize) + 2; x++) {
				if (x >= 0 && x <= mapSize && y >= 0 && y <= mapSize) {
					level[x][y].render(g);
				}
			}
		}
	}

And also the Camera tick method (also an important part):


	public void tick() {
		if (input.getKey("W")) {
			y += Level.tileSize;
		} else if (input.getKey("S")) {
			y -= Level.tileSize;
		}

		if (input.getKey("A")) {
			x += Level.tileSize;
		} else if (input.getKey("D")) {
			x -= Level.tileSize;
		}
	}

I’ll give you a hint, look at your for loops and think about why only parts of the map around the player are being rendered. Instead of immediately throwing us the problem, sit and think about it for a little bit.

I understand what you’re getting at, but I do attempt to fix my issues before asking for help (since I’ve had the past few days free, I’ve been non-stop coding random features).

From debugging I can tell all tiles are there, they can be interacted with and they can be changed/replaced/added.

I still have no idea why it isn’t rendering tiles that are there, I’ve tried modifying tile co-ordinates and tried to forcefully render specific tiles are specific locations to see if they show up.

First thing to do is refactor the loops into readable code.

Then print out indices to see if they are correct when you move along. Start with the upper left corner.

It seems my entire level co-ords are all muddled. The camera starts are 0,0 at the beginning of the level array, I assume, but moving the camera around sends the values into negatives.

I am super confused, are there any examples of top-down cameras/level movement? From my searching before posting here, I could only find examples using libraries built-in cameras.

Edit: Managed to get somewhere, now the camera moves and there is a 128x128 tile map (the size specified upon level creation).

The map still seems to move around in the fixed position though, and doesn’t actually scroll through the tiles.

New render method for level:


	int mapVisibleStartX = 0, mapVisibleStartY = 0;
	int mapVisibleWidth = mapSize, mapVisibleHeight = mapSize;

	for (int y = mapVisibleStartY + ((int) camera.getY() / tileSize); y < (mapVisibleStartY + mapVisibleHeight) + ((int) camera.getY() / tileSize); y++) {
		for (int x = mapVisibleStartX + ((int) camera.getX() / tileSize); x < (mapVisibleStartX + mapVisibleWidth) + ((int) camera.getX() / tileSize); x++) {
			if (x >= 0 && x < mapSize && y >= 0 && y < mapSize) {
				level[x][y].render(g);
			}
		}
	}

I love to quote myself. :wink:

The way games have the illusion of the player standing still while the world moves around him is not as literal as you think. Generally, the player moves as normal and the graphics instance is translated so that it is centred on the player. This is a camera, it’s only rendering the things around the player, and is centred on the player.

What graphics library are you using? From your code it seems to be Slick but I’m not sure. If it is Slick, there is a translate method for the Graphics class you can use.

Oh, and refactor your loops like the others have been saying. It also helps to put comments down to know what your code is doing.

To me the code is readable, each to their own I guess.

I’ve managed to find some info on scrolling levels, thanks anyway for your help folks.

I’ll update the thread once I’ve got working code for anyone else who may have this issue in the future.

Correct me if I am wrong, but didn’t you just expect other people to read it and help ?

Yes, it’s readable to you and I’m sure that everyone here could figure out the general idea of what you’re doing, but that takes time.

However, generally the longer the line of code the harder it is to read, and people are lazy. I don’t want to look at a for loop and think, hmm what does “x” start at. If you do something like:

int mapVisibleStartX = 0;
int mapVisibleStartY = 0;
int mapVisibleWidth = mapSize;
int mapVisibleHeight = mapSize;
int left_camera_bound =  mapVisibleStartX + ((int) camera.getX() / tileSize);
int right_camera_bound = (mapVisibleStartX + mapVisibleWidth) + ((int) camera.getX() / tileSize);
int top_camera_bound = mapVisibleStartY + ((int) camera.getY() / tileSize);
int bottom_camera_bound = (mapVisibleStartY + mapVisibleHeight) + ((int) camera.getY() / tileSize);

for (int y = top_camera_bound; y < bottom_camera_bound; y++) {
   for (int x = left_camera_bound; x < right_camera_bound; x++) {
      if (x >= 0 && x < mapSize && y >= 0 && y < mapSize) {
         level[x][y].render(g);
      }
   }
}

it’s much kinder for the people you’re requesting help from. It took me a few seconds to actually determine what your code did. Mine I can just read and say "Oh we are looping through all of the tiles within the camera bounds. (Granted I wrote the code, so maybe mine isn’t really readable either, but it’s a start.)

Hello again thedanisaur! I see how that may be more readable to some, but to me that many variables looks unclean.

Still can’t manage to get it past this (https://gfycat.com/FoolishOffbeatHornedviper) state. All tiles now seem to be drawing but the level still doesn’t follow the player.

P.S. To whoever asked, I don’t use an engine. This is put Java Graphics.

Thing is you don’t need half of them, your code collapses to this (and could collapse further):

int left_camera_bound =  ((int) camera.getX() / tileSize);
int right_camera_bound = mapSize + ((int) camera.getX() / tileSize);
int top_camera_bound = ((int) camera.getY() / tileSize);
int bottom_camera_bound = mapSize + ((int) camera.getY() / tileSize);

for (int y = top_camera_bound; y < bottom_camera_bound; y++) {
   for (int x = left_camera_bound; x < right_camera_bound; x++) {
      if (x >= 0 && x < mapSize && y >= 0 && y < mapSize) {
         level[x][y].render(g);
      }
   }
}

regardless this is not what you want. Best case is when you’re in the start position you render the entire map (and then some :wink: ).

Off topic, but:

Never go into any kind of professional programming field then…

Still haven’t managed to figure it out, further help would be appreciated.

This is a bit of a stab in the dark, but to me it looks like the tiles are getting drawn at their positions in the world, without being transformed by the camera. It doesn’t look like the camera has any effect on where the tiles show up on the screen.

I tried (as a temporary measure) to access the camera directly, but doesn’t seem to make a difference. I updated the Tile constructor to be…

setBounds(x - (int) Game.camera.getX(), y - (int) Game.camera.getY(), Level.tileSize, Level.tileSize);

You need to change the render positions, not the actual positions.

Since you’re not using an engine, you could transform it all yourself. Just add something like


// in render code
g.fillRect(tileX * tileWidth - cameraX, tileY * tileHeight - cameraY, tileWidth, tileHeight);

This way everything gets offset by the camera. This is really tedious but if normal Java graphics has a translate method, you could use that instead.

Your code is working sort of. It’s rendering only the parts where the “camera” see but nothing is actually getting translated as required.

Using this solution isn’t something I’m keen on using unless there’s no other way I can simply render/move tiles around in the Level class. With this solution, I’d need to pass the camera position to the tiles, which I don’t feel like doing. I’ve tried many solutions on Google but can’t seem to stop the same map position following the camera position, so not seeing any new parts of the map.

Current attempt code:


	int xStart = Math.max(0, cameraX - (Main.getWid() / tileSize));
	int xEnd = Math.min(Main.getWid(), cameraX + (Main.getWid() / tileSize));
	int yStart = Math.max(0, cameraY - (Main.getHei() / tileSize));
	int yEnd = Math.min(Main.getHei(), cameraY + (Main.getHei() / tileSize));

	for (int x = xStart; x < xEnd; x++) {
		for (int y = yStart; y < yEnd; y++) {
			getTile(x, y).render(g);
		}
	}

Why don’t you like your solution?

With your current setup I don’t see a simple way around it, at some point your level has to know about the camera or the camera has to know about the level.

Edit: hint, your camera should definitely not care about the level.

I understand that, and the level knows of the cameras x/y position. I just don’t want the tiles to know of the cameras position, sorry if the previous post came off as different.

My current solution I didn’t like because it appeared to be dragging on other elements whenever the map moved. Plus, for every tile render I’d have to do “x + camera.getX()” and same for y.

The way I would absolutely LOVE to do it is if I could handle the level scrolling all from the camera/level classes, like I am trying to do in the level render.