Smooth screen scrolling?

Hello guys,

I cannot figure out how to move from here, I kind of placed myself in a bad position…

Right now when moving in my game it moves with 1 tile per move, The tiles are 64*64 so it looks realy stupid when i want smooth movement. What i mean with smooth movement is that i want my map to be able to draw a half tile and not only whole tiles.

Here is my current code:


	public void drawLevel(Graphics g2d, int screenX, int screenY){
		drawX = 0; //X cordinate for the map to draw at
		drawY = 0; //Y Cordinate for the map to draw at
		
		for(int y = screenY; y < screenY + 10; y++, drawY += 63){
			for(int x = screenX; x < screenX + 13; x++, drawX += 63){
				switch(level1[x][y]){
				case 1: 
					g2d.drawImage(grass, drawX, drawY, grass.getWidth() * imageScale, grass.getHeight() * imageScale, null);
					break;
				case 2:
					g2d.drawImage(water, drawX, drawY, water.getWidth() * imageScale, water.getHeight() * imageScale, null);
					break;
				case 0:
					g2d.drawImage(temp, drawX, drawY, temp.getWidth() * imageScale, temp.getHeight() * imageScale, null);
					break;
				}
			}
			drawX = 0; //Resets the X cord to draw at for the next line
		}
	}

The screenX and screenY is incremented using screenX++; in the player move methods.
the scrolling is working but i just cannot figure out how to make the scrolling smooth and not only moving tile per tile.

I thought of change it all to floats but wouldn’t that mess with my 2D array?
Also i cannot draw the whole array since its a big map of 500 tiles so i need to draw only whats on the screen.

A quick glance at your code makes me suggest it’s because you’re adding a tiles’ width each step.

, drawX += 63){

If it was incrementing by 1 each step, it would go smoothly.

That clumps up all my tiles in the top left corner… I tried changing it to drawX += 1 and it wont draw the map just place all the tiles in the top corner.

Theese images im drawing is 77 tiles but im scaling them up to 6363.
Reason i put the drawX+= in the for loop was to make the tiles not like draw on top of eachother since x is just incremented with 1 and 1 cordinate compared to 63 wont work if u know what i mean…
I just suck at explaining… Hope you understand me :S

Are you sure i dont need float variables to do this task im after?

[quote]Are you sure i dont need float variables to do this task im after?
[/quote]
The major difference between a float and a integer is that a float can have a decimal. Now while it is quite useful, it is unneeded here as the x and y variables draw to a pixel origin on the screen. But as you can’t have a fraction of a pixel, you don’t need decimals.

Maybe you need to decouple the drawing of tiles from the viewport (the camera, so to speak)

Have you tried drawing all your tiles (plus a few extra offscreen tiles) into a BufferedImage, and then position the image into the canvas based on the camera position?

Something like this:



int cameraXpos = ...
int cameraYpos = ...
int cellWidth = ...

BufferedImage compositionCanvas = new BufferedImage(...);
Graphics graphicsContext = ... // Your main window rendering context

...


//Rendering Loop
while(doRender)
{
   //This method draws the tiles into the compositionCanvas image.
   //The tiles are drawn based on the tilemap coordinates 
   DrawTiles(cameraXpos/cellWidth, cameraYpos/cellWidth, compositionCanvas);

   // Now draw the composed image into the app context, displacing it as needed.
   GraphicsContext.drawImage(compositionCanvas, cameraXpos, cameraYpos, null);

}

It’s a very raw code example, just meant to get the idea across. Essentially, draw your tiles completely (say, if the screen shows 1010 tiles at one time, draw 1212) and then use the .drawImage method to position the resulting image smoothly.

You can also use this method to draw all tiles at 1:1 scale, and then scale up the resulting image by using the width and height attributes of the .drawImage method.

Am I making sense here? :persecutioncomplex:

How often do you call drawLevel() and at what point in your program is it called?

Also, if you always start at drawX = 0 and drawY = 0, wouldn’t drawLevel() render the image on the screen the same way everytime?

What I’m thinking is that you should start drawing your tiles depending on the movement of your character, so drawX and drawY should be initialized not to 0, but to a value that is relative/represents the position of your character at any given point in the game.

BTW: I have no idea what game you’re developing and how things look like so I’m shooting blind here :smiley: Screenshot, maybe?

The map rendering is not a problem… My map is rendered as it should.

My problem here is that when the player walks the screen moves with 64 pixels each time u press a move button. Think how movement is done in the old pokemon games.

The method i posted in the first post is my render method which is called in the update method and is a part of the game loop.

My goal is to make movement smooth like instead of jumping 64 pixels each time render is called jump maybe 1 pixel so movement gets more free.

Understand me?

I do understand. What I’m suggesting is that, instead of drawing directly to the screen, you first do exactly what you are doing, draw it all into an intermediate surface, and then draw that image into the screen with the proper position adjustment so it is smooth.

Think of it as taking a photo of your map, and the taking that photo and placing it into the frame in the position it needs to be at.

That way, only thing you need is to add an extra step to your pipeline instead of reworking the rendering algorithm, so if you have:

Movement -> Draw Tiles -> Screen

You’d have

Movement -> Draw Tiles -> Move Intermediate Image -> Screen

The bit about rendering more tiles is just to make sure you don’t get empty spaces when positioning the intermediate image. In essence, the intermediate image is larger than the screen area, and you’re just moving it around to “frame” the parts you want.

Ah well now I understand you.

It was confusing because it looked like the code you posted in the OP was the code to draw the map.

Where’s the part of the code that draws the player?

Upgraded my code to this:


	public void drawLevel(Graphics g2d, int screenX, int screenY){
		drawX = 0; //X cordinate for the map to draw at
		drawY = 0; //Y Cordinate for the map to draw at
		
		for(int y = screenY; y < screenY + 10; y++, drawY += 63){
			for(int x = screenX; x < screenX + 13; x++, drawX += 63){
				switch(level1[x][y]){
				case 1: 
					levelg2d.drawImage(grass, drawX, drawY, 63, 63, null);
					break;
				case 2:
					levelg2d.drawImage(water, drawX, drawY, water.getWidth() * imageScale, water.getHeight() * imageScale, null);
					break;
				case 0:
					levelg2d.drawImage(temp, drawX, drawY, temp.getWidth() * imageScale, temp.getHeight() * imageScale, null);
					break;
				}
			}
			drawX = 0; //Resets the X cord to draw at for the next line
		}
		
		g2d.drawImage(mapRenderImage, 0, 0, 800, 600, null);
	}

While the mapRenderImage is initiated together with the levelg2d in the class initialization method like this:


mapRenderImage = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
		levelg2d = mapRenderImage.createGraphics();

This did not make any difference in the game… When movement is happended for example: if Player press “D” do screenX++; then i put it into the parameters to drawLevel method… Maybe im overthinking this and thats why i cannot see the easy solution… But it still makes every click “jump” 63 pixels everytime i want to move the screen…

EDIT:
I know 100% sure this problem is appearing just because im using the drawX and drawY in the levelg2d.draw to get the tiles lined up correctly and not intersecting eachother in the top left. But i cannot find anything to replace it with… :frowning:
I know thats the reason :S

For people who are trying to help me here, screenX and screenY is the cordinates of the top left corner of the screen that should be visible. I increment it when the player presses a movement button… Example: screenX++;

[quote=“Rakso,post:10,topic:41877”]
In that case, maybe the problem is with how you’re deriving screenX and screenY since those are the values that pretty much dictates where drawLevel() draws the tiles.

Where’s the code that determines the value of screenX and screenY to be used when drawLevel() is called?

Ok i solved the problem with the screen now not jumping… But i came with another thought to mind…

Now if i want every keypress to lets say go 10 pixels in the direction the key was pressed… The drawing looks kind of laggy when the drawing is done that way…

Does anyone have suggestions for this?
Im using a player velocity of 10… so doing like this: screenVelocityX += playerVelocity

P.S. Thanks to Oskuro for the good idea of drawing everything to an image then drawing the image to the screen… It helped me out.

EDIT:
Solved that one too by removing the timer for movement and then decreasing the velocity. Thanks agian everyone who spent time helping!