tilemap scrolling and tile collision

i’ve got a tilemap drawn on screen and scrolling when the player moves, however the player moves faster than the tilemap scrolls and ends up going offscreen
also, any tiles the player should collide with are being detected after he has passed them…
i notice at the start of the level when the player can move a little before the screen starts to scroll, the relative tile position is detected fine, but when the screen scrolls, the tiles pass the player more quickly, but the relative position of the player (in terms of tiles) moves at the same rate as if the screen wasnt moving
any ideas?

well, make scrolling faster, actually same speed as player, maybe it will fix your collision detection also…

im not sure how to do that though… here is the code I’m using to draw the tilemap in relation to the player’s position


// width of tilemap in pixels
    	int mapWidth = tiles.length * TILE_SIZE;
    	// calculate offsetX using screen width (800)/2 and playerX position
    	int offsetX = (getWidth() /2) - Math.round(player.getX()) - TILE_SIZE;
    	offsetX = Math.min(offsetX, 0);
    	offsetX = Math.max(offsetX, getWidth() - mapWidth);
    	int offsetY = getHeight() - (tiles[0].length) * TILE_SIZE;
        int firstTileX = (-offsetX) / TILE_SIZE;
        System.out.println(""+firstTileX);
        int lastTileX = firstTileX + (getWidth() / TILE_SIZE) + 1;
    	for (int y = 0; y < tiles[0].length; y++)
        {
        	for (int x = firstTileX; x <= lastTileX; x++)
        	{
        		if (tiles[x][y] != null)
        			g.drawImage(tiles[x][y], (x*TILE_SIZE)+offsetX, (y*TILE_SIZE)+offsetY, null);
        	}
        }

thanks for your help

“scrolling” should be based on the player’s position, they shouldn’t be independant

Players position + half of players width - half the width of the screen is the x position where you want to start drawing the tile map. As long as you are storing the player’s position relative to the tilemap there should be no problems. And obviously you need to detect when it cannot scroll any longer. That can be done iwth simple Math.max/min calls though.

It sorta looks like your doing something like that anyway though. If you want really basic collision you can just make two rectangles out of whatever you want to test and call .intersect()

p is player and o is object.
As in if (new Rectangle(p.x, p.y, p.w, p.h).intersects(new Rectangle(o.x, o.y, o.w, o.h)) {}

If you want to be more sophisticated and line things up on the edge collided (better), then you need to do more math. Move things one at a time, x axis first, check for collision, if there is one check your velocity and line it up with the proper edge of whatever it collided with. As in if you were moving left, line it up with the right edge of the object you hit. Then do down, that removes the problems of doing both at the same time and going diagonally through something you wouldn’t have normally hit. I have to go to a class now, but ill show some code later, for both things I described.

it’s the scrolling that’s affecting tile collision, so i need to fix that first. What you suggested, when i change the offsetX to that formula, the scrolling goes in the opposite direction, and the player stays on the same tile the whole time, which at least as better than him running over more tiles on screen than he actually is as far as the code is concerned!.
I’m losing it here! lol… I’ve been at this for days just can’t get my head round it at all
I’m not bothered about the tile collision, just getting the scrolling to work properly…

thank you for your help

edit : here’s a link to a video showing what’s happening, but not with your suggestion, just in general…
sorry about the flickering… the code i was given to work on was supposed to have dealt with that already!

http://www.geocities.com/petrucciboy20/video.wmv

What books do you have? I would suggest Developing Games in Java by David Brackeen. Thats a good book, except chapter 6 which is written by someone else :. You can find all the code to his book at
http://www.brackeen.com/javagamebook/#download

Check out chapter 5’s code that should have everything you need. And here is an exert from my renderer of tile maps, which started as an exact clone of his but ive modified it heavily since I went trhough his book a few years ago.

public void draw(Graphics2D g, TileMap map,
        int screenWidth, int screenHeight)
    {
		ImageSFXs sfx = new ImageSFXs();
        Sprite player = map.getPlayer();								//gets the player
        int mapWidth = tilesToPixels(map.getWidth());					//width of the tilemap in pixels
		int mapHeight = tilesToPixels(map.getHeight());					//height of tilemap in pixels
		
		
        int offsetX = screenWidth / 2 -
            Math.round(player.getX()) - TILE_SIZE;						//offset the tilemap should be drawn at
        offsetX = Math.min(offsetX, 0);									//offset cannot be greater than 0
        offsetX = Math.max(offsetX, screenWidth - mapWidth);			//offset cannot be less than the differnce between the screen width and the map width
		// get the y offset to draw all sprites and tiles
        int offsetY = screenHeight / 2 -
            Math.round(player.getY());									//same thing with the y axis
        offsetY = Math.min(offsetY, 0);									
        offsetY = Math.max(offsetY, screenHeight - mapHeight);

        // draw black background, if needed
        if (background == null ||
            screenHeight > background.getHeight(null))
        {
            g.setColor(Color.black);
            g.fillRect(0, 0, screenWidth, screenHeight);
        }

        // draw parallax background image
        if (background != null) {							
            int x = offsetX *
                (screenWidth - background.getWidth(null)) /
                (screenWidth - mapWidth);								//parallax scrolling, draw the background relative to where the player is
            int y = offsetY *
				(screenHeight - background.getHeight(null)) /
				(screenHeight - mapHeight);
		

            g.drawImage(background, x, y, null);
        }

        // draw the visible tiles										//here we clip the field so we dont waste time drawing tiles that arent on screen
        int firstTileX = pixelsToTiles(-offsetX);						//reverse x offset, remember we created it negative, find which tile to start drawing
        int lastTileX = firstTileX +
            pixelsToTiles(screenWidth) + 1;								//the last tile drawn is one wider than the screen width, otherwise the last column will be blank when its not exactly one tile;s width on screen
        for (int y = 0; y < map.getHeight(); y++) {
            for (int x = firstTileX; x <= lastTileX; x++) {
                BufferedImage image = map.getTile(x, y);
                if (image != null) {
                    g.drawImage(image,
                        tilesToPixels(x) + offsetX,
                        tilesToPixels(y) + offsetY,
                        null);
                }
            }
        }


        // draw sprites
        Iterator i = map.getSprites();
        while (i.hasNext()) {
            Sprite sprite = (Sprite)i.next();
            int x = Math.round(sprite.getX()) + offsetX;				//add the offset to the sprites' and player's positions before drawing
            int y = Math.round(sprite.getY()) + offsetY;
            g.drawImage(sprite.getImage(), x, y, null);
        }
		
		// draw player
        g.drawImage(player.getImage(),
            Math.round(player.getX()) + offsetX,
            Math.round(player.getY()) + offsetY,
            null);
    }

That is what I use when I make tile-based games. I don’t think i explained terribly well, and it is hard to get your brain wrapped around it the first time. Ill go read a book and see how they describe it.

Those comments were perfectly lined up in my editor :\

If your brain is having trouble with it, you might want to just draw the whole map, and ignore parallax scrolling for now, and just get the scrolling/colliison working. For that you only need the following exerts of the code I wrote above.

int offsetX = screenWidth / 2 - Math.round(playerplayer.getX())  -TILE_SIZE

that keeps the player centered if you add that to the player’s x draw.

offsetX = Math.min(offsetX, 0);
offsetX = Math.max(offsetX, screenWidth - mapWidth)

And that will make it so that when you scroll all the way to one side of the tilemap, it wont show a void area, the map will stop scrolling and the player will move out of the center of the screen.

thanks very much, ironically, i have that book and have been following it
but the player still runs faster than the tiles scroll, so he runs off the screen!
very very frustrating lol…
what could possibly be causing that!?

how do you not know that!? … I get the feeling you were just copying the code from the book. You need to understand it, and you’ll understand the problem. Your scrolling needs to be focused around the player. You get his (x,y) coordinates and draw the world around him based on that.

Imagine that level has 2000 pixels in width. Screen can show only 1000. Your player is at 750th pixel at the moment. What pixels of world you need to draw? Answer is 1000 pixels around 750th pixel, that is starting 750-1000/2 and ending 750+1000/2, which in abstract is
starting: player.posX() - screenWidth/2, ending player.posX() + screenWidth/2.

I’ve never worked on a scrolling game but this should work, you only need to figure how that relates to your tiles and other stuff, like drawing world when you reach the end (obviously formula above will not work and you will need implement special cases)

Heh, now that I acutally look at your code it is the code from that book, and basically what I showed you.

But it looks like your converting from tile to pixel location twice. You divide offsetX by Tile size when you make firstTileX, offsetX appears to already be representing pixels.
See what happens when you remove the / TILE_SIZE. Though i dont see how that would fix it if you “run” off the screen. This would just make you draw all the wrong tiles.