Slow down; You're moving too fast! (smooth tile transition problem)

The game I am creating is tile-based. Movement is per-tile, as one would expect a tile-based game to be. This means that the player presses to go left once, the character automatically moves to the left the space of a single tile.

I decided that it jumping from tile to tile just didn’t look professional enough(http://glasszee.tumblr.com/post/24288781615/camera-movement-is-still-choppy-moving-one-tile), so I added a certain thing that moved the camera to the left bit by bit. Say the distance between a tile was 32 pixels. What it does in the video is go straight from 0 to -32. But I changed it so that you press left, and the x coordinate will go 0, -1, -2, -3, -4, -5, -6, all the way to -32. I printed the x coordinate out, and it’s apparently working. The problem is that it’s moving so fast that you can’t even comprehend that it’s moving. Which isn’t surprising-- at 200 frames per second, the difference between 2 frames and 32 frames won’t seem like that much.

How do I slow down the time between the 0, -1, -2, -3, etc? Maybe OpenGL has a way for it to wait a certain amount of time before going to the next frame, while not stopping other areas of the code?

EDIT: Here is some relevant code that you may want to see.

if(isMoving){
		while(x == 0){	
			switch(direction){
			case 0: desiredY=yAdd+(scale*s);//scale*s is the length of a tile
			break;
			case 1: desiredX=xAdd+(scale*s);
			break;
			case 2: desiredY=yAdd-(scale*s);
			break;
			case 3: desiredX=xAdd-(scale*s);
			break;
			}
			x = 1;/*this wonky thing is to have this happen once every 'isMoving' occasion,
                       or else the desiredX or Y will always be (scale*s) more extreme than xAdd and it'll go on forever.*/
		}
	}		
			if(xAdd<desiredX){ /*the reason it's not a 'while' is because, to my understanding, it only renders when it reaches
                                                    Display.update(). A 'while' would have it move to -32 before updating even once.*/
				xAdd+=1;
			} else if(xAdd>desiredX){
				xAdd-=1;
			} else if(yAdd<desiredY){
				yAdd+=1;
			} else if(yAdd>desiredY){
				yAdd-=1;
			} else {
				isMoving=false;
				x = 0; //now it's not moving anymore, so everything resets.

//glBindTexture, glBegin, etc.
			}

Perhaps add a ‘graphics’ update along with your ‘logic’ update to your code.

I’m not sure how you’re managing your game loop currently, but a normal thing is to define a number of ‘update cycles’ that should happen per second, and only update that number of times rather than allowing your game to update every time you paint things. In a way, this will increase your FPS (Because a lot of the time, you’ll be skipping your update step and just painting) and if your game is played on a platform that is slower for whatever reason you’ll have more consistent game play.

Instead of having this shift in your render code, you should put it into your logic code, or into another method that is called at some specific rate to ensure that it’s only updated X times per second. Whether this falls into a real ‘logic’ update or into a secondary sort of ‘graphics’ update function is up to you.

Someone else might be able to give you a better idea of how to do it take a peek at: http://www.java-gaming.org/topics/game-loops/24220/view.html if you haven’t.

See yea, I read that thread before and set up a ‘variable timestep’. The problem is, that’s one of the things I read where I was just blindly following what it said. I don’t actually understand it, but I’ve had this ‘delta’ variable for a long time and I don’t even know what to do with it. Is that how I fix the problem?

The delta variable is used to determine that no matter how long your updates/rendering (I can’t remember which, or if it’s both. Anyone?) takes, gameplay will always be smooth.

Is that the solution to my problem? The delta value? I don’t get how it helps.

Right now my game loop is:

while(!Display.isCloseRequested()){
    GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);
    //Poll player's keys
    //get player's current position
    //render the tiles based off of the position(it only renders tiles near the player)
    //update FPS
    //print FPS
    //update display
}

Where do I put this ‘update cycle’, and which part is being cycled? The link you posted didn’t talk about update cycles.


MAX_TIME_BETWEEN_LOGIC_UPDATE = something;
MAX_TIME_BETWEEN_DISPLAY_UPDATE = somethingElse;
accumLogic = accumLogic + delta;
accumDisplay = accumDisplay + delt;

public void updateMethodThinger( ... ) {

    while(accumLogic >= MAX_TIME_BETWEEN_LOGIC_UPDATE) {
        accumLogic = accumLogic - MAX_TIME_BETWEEN_LOGIC_UPDATE;
        updateLogic();
    }

    while(accumDisplay >= MAX_TIME_BETWEEN_DISPLAY_UPDATES) {
        accumDisplay = accumDisplay -MAX_TIME_BETWEEN_DISPLAY_UPDATE;
        updateDiaply();
    }

    render();
}

This is butchered, semi-pseudo code based on what Notch did for his Metagun project, one of the LD’s. What it does is:
Stores the accumulated time since the last time your updateLogic/updateDisplay was called. This is delta + remainder from the last time this method was called.
Calls the updateLogic/updateDisplay once for each time the accumLogic/accumDisplay is greater than or equal to the constant listed at the top.

Why this is helpful? Let’s say that you don’t care what your FPS is, because it’ll differ too greatly between different computers to actually be of use to you when you’re writing your logic (Case in point, using the libgGDX library I get a smooth 60-63 on my desktop, 40-63 on my tablet and 30-90 on my android phone.) So, instead, you decide I want to have exactly X logic updates a second. You set the constants to the amount of time there should be between updates to cause this: (1000000000 / 60 for 60 updates a second, but it all depends on whether your delta is returning nanoseconds, etc).

Either way, when you hit that inner loop, it’ll check whether the accumulated time is large enough to warrant an update or not. If it is? Good, then call as many updates as needed. If not, continue to accumulate time. Why does this help you? Let’s say you have 60 updates a second. All’s going good, you’ve got something like a 200 FPS which you mentioned before, which means that you’ll be calling an updateLogic() only once every 3-4 frames. Then, something happens (Another process starts up and hogs your CPU, you get a swarm of enemies on the screen, whatever) and you’re updateLogic() is suddenly taking a lot more time and you’re now at 30FPS? Well, instead of just completely lagging up the game world so that you’re only getting one update per frame, you’ll be calling updateLogic() twice per frame to keep the number of update ticks close to what you actually want.

Now, how does this help you for your issue of slowing down your movement? You put your game’s logic in the updateLogic() method. That is the stuff that happens when your character is told he needs to move, or process an enemy’s UI, etc. And you put the display’s logic in the updateDisplay() method. That is the stuff you do when you need to check whether your animations should advance, your screen should move X pixels, etc.

As for where it goes in what your update loop looks like? Well, it should probably go before the rendering is done, with the last ‘update display’ chunk being inside of the updateDisplay() method.

I’m not sure what to put into display logic and game logic. Here is what I have so far:

arranged like this:

//CODE

description of above code


GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);

This is has got to be display logic…

	p.pollKeys();

It’s checking to see if a move has to take place, so game logic…

		int[] playerPos = p.getPosition();
		int playerX = playerPos[0];
		int playerY = playerPos[1];
		
		while(playerX>=256-16){
			playerX--;
		}
		while(playerX<=16){
			playerX++;
		}
		while(playerY>=256-16){
			playerY--;
		}
		while(playerY<=16){
			playerY++;
		}

This is to prevent it from getting out of the array. It is game logic.

		m.renderTiles(playerX, playerY);

This is actually calling the tiles to be on the screen so it’s display.


		updateFPS();

		f.printMsg(-width/2, -height/2, "FPS : " + Integer.toString(thisFPS));

Game, I guess. It’s not like it has to do with getting something on screen.
EDIT: Maybe updateFPS() is game logic and f.printMsg is display logic?


			Display.update();

I assume this is the equivalent of the render() at the end…

Anyway, when I arrange it like how it is above, it becomes black most of the time and occasionally flashes with what’s supposed to be on the screen. Sure, it doubles my framerate, but the actual map only appears intermittently. Furthermore, it doesn’t even seem like it’s playing the animation.

I don’t know, it just seems kind of subjective which is which.

Ah, egads. A lot of what you just showed me in the last post is taken out of its context (Meaning showing snippets without any information about where/how they get called, what reads them, etc) so I can’t say what’s right/wrong in them.

From what you’ve posted, you’re basically polling every frame to check the state of some keys and updating something based off of them? Is this meant to actually move your character around or move a camera around. The difference there is whether it’s updating the actual game’s state (Think logical back-end) or whether it’s just updating variables that are used to display to the screen?

This really boils down to how you’re separating your UI from your game’s Logic. If you haven’t really figured that part out yet, then it’s probably a good idea for you to sit down and figure that out before you really worry about how you’re going to draw it onto the screen.

Yo thanks for the help. Yea the problem was that the renderTiles() was doing too much. I separated the part that did the movement into its own method, then put that method into the display while-loop. Thanks for the help, your post was exactly the answer I needed.