[SOLVED] Skip frames

I have trouble with my game loop. The one I have can cause objects to get stuck or teleport through other objects. I know it’s caused when the FPS is low and the game tries to put the objects where they are suppose to be. But it ignore hit detection. My idea is to make the game not render all the frames when it runs slow, to try to get more time for the logic. But I’m not sure how to do that.

@Override
    public void run(){
        while(true){
            double delta = (System.nanoTime() - lastUpdate) / 1000000000.0;
            lastUpdate = System.nanoTime();
            
            world.update(delta); 
            screen.repaint();
            
            if(!maximumFps){
                //100000 convert nanosecound into milisecound. It's what 1 milisecound is in nanosecounds
                try{ Thread.sleep((lastUpdate-System.nanoTime() + optimalTime) / 1000000); }catch(Exception e){}
            }else{
                try{ Thread.sleep(1); }catch(Exception e){}
            }
        }
    }

What exactly are you doing inside world.update() (i think thats your global “gamelogic update” method)? Also are you using any libraries or pure java2d? A bit of code of screen.repaint() and world.update() would be very helpfull.

Also this:


try{ Thread.sleep(1); }catch(Exception e){}

won’t cause any noticable change to the current behavior, as you set the thread to sleep for just 1 millisecond.

I thought ur loop was really weird…

I like to program loops like this:


public void run(){
	long start, end, time, sleeptime;
	while(true){
		try{
			start = System.currentTimeMillis();
			
			tick();
			render();
					
			end = System.currentTimeMillis();
			time = end - start;
			sleeptime = 1000/60 - time;
			if( sleeptime < 0 ) sleeptime = 0;
			Thread.sleep(sleeptime);
		}catch(Exception e){}
	}
}

Oh, and about skipping frames, never do actions based on frames, but on time…

The loop wasn’t that bad, and doesn’t cause framelags. And where does he do actions based on frames? He updates the game using the delta time (as everybody should do) :).

An advice to both of you:


/* Works but isn't very nice nor very capable of 
 * beeing used in a "serious" game because it will just loop infinitely. */
while(true) {
...
}

/* This one is quite better, because you can control the condition better. 
 * If you choose to quit your game and maybe move back to a menuscreen 
 * you could stop with running = false: */
while(running) {
...
}

Okay, I going to fix the while(true) issue later. The problem I have is that, at low fps the objects will jump through other objects, since I’m currently using…

@Override
    public void update(double delta){
        addX(25.0 * delta);
        addY(25.0 * delta);
    }

…to move objects. what I need to do is let the game logic catch up with the frames. That way I was thinking of doing that is to not skip frames. So the game logic still act like it’s running in 60 fps, when the player only see 30

So lets say your delta time is about 0.01 seconds. It means you’re moving your object about 0.25 pixels every frame and that means (with a framerate of about 60 fps) you move your objects 15 pixels every second. If you check for collisions every frame, there should be no problem at all.

You’re gamelogic happens every frame, so you cannot “limit” it to the frames. That means every time something is drawn, the gamelogic is calculated before. Also you’re logic doesn’t “skip” frames, as your frames don’t skip frames. if you halt your gameLoop because of fps limitation (thread.sleep()), no logic will be done, but also no rendering will be done.

Another case would be, if you would use a seperate thread for your gamelogic. But i don’t think thats the case here.

You don’t understand the issue. if the framerate becomes to low, the detla time can go up to 0.99 which can cause the object to jump through other objects, because it will be teleported 24 px.

Anyway, I know my code don’t skips frames. That is what I’m trying to implement. Let say I have two threads. one for game logic, and one for the frames. Wouldn’t that cause issues/instability?

No, don’t do this. Having two threads is a terrible idea. This forum has a whole board dedicated to things like loops. Just search for game loop and implement one of them.

That’s what I thought, and guess how I got hold of this one I have, I was thinking of having some if statement to skill screen.repaint(); to skip frames. But I’m not exactly sure how to do it.

That’s a known problem with variable timestep game loops. A solution is to make frames of constant length by using fixed timestep game loop. Now, let’s make a game loop that keeps the game logic at the same rate and renders a frame if the maximum fps is not reached.

Let’s start by making some variables for the game loop.


long now = getCurrentTime();
long gameTime = getCurrentTime();

// Updates per second
long ups = 60;
// The time to update the logic once.
long timeForLogic = 1000 / 60;

// For frame skipping
int framesSkipped= 0;
int maxFrameSkip = 5;  // Skip a maximum of 5 frames before rendering

// For fps count
int fps = 0;
int frames = 0;
long lastFpsCount = getCurrentTime();

Here, [icode]getCurrentTime()[/icode] is just a method that returns the current time in milliseconds. Now, let’s write the inner game loop. For better results, we separate rendering and logic.

First, we need to only update the logic only when it is required. Did you notice that [icode]gameTime[/icode] variable? It’s is what we use to check when the update is required.

So if the condition [icode]now + timeForLogic > gameTime[/icode] is met, we need to update. Ok, but wee also need to check for frame limiting. So change the condition to [icode](now + timeForLogic > gameTime) && (framesSkipped < maxFrameSkips)[/icode] to make sure we render a frame in between. So now the code for the game loop will be


while (running)
{
    framesSkipped = 0;
    now = getCurrentTime();

    // Update only when required
    while ((now + timeForLogic > gameTime) && (framesSkipped < maxFrameSkips))
    {
        world.update();

        gameTime += timeForLogic;
        framesSkipped++;
    }

    // Render to screen
    screen.repaint();
    
    // calculate fps
    frames++;

    if (now - lastFpsCount >= 1000)
    {
        fps = frames;
        frames = 0;
    }
}

And now, this limits the updates you have to do in a second, but rendering how many frames it can. Be careful that it uses the total cpu. To limit that, just sleep by 1 ms at the end of fps count.

The title is: “Skip frames” and:

[quote]My idea is to make the game not render all the frames when it runs slow, to try to get more time for the logic.
[/quote]
This doesnt look like using time

long lastTime = System.nanoTime();
          double nsPerTick = 1000000000D / 60D; //~60fps
      
      int ups = 0;
      int fps = 0;
      
      long lastTimer = System.currentTimeMillis();
      double delta = 0;
      
      while(game loop not quit blub) {
         long now = System.nanoTime();
         delta += (now - lastTime) / nsPerTick;
         lastTime = now;
         boolean renderOK = false;
         while(delta >= 1) {
            ups++;
            update();
            delta -= 1;
            renderOK = true;
         }
         if(shouldRender) {
            fps++;
            render();
         }
         if(System.currentTimeMillis() - lastTimer >= 1000) {
            lastTimer += 1000;
            System.out.println("frames: " + fps + " | updates: " + ups);
            fps = 0;
            ups = 0;
         }
      }

Use this. Just found it on the forum, I also use game loops like this and they have never failed me. Smaller code doesn’t always make for better code.


//will get the fps
public int finalFrames = 0;

public void run() {
      long lastTime = System.nanoTime();
      final double amountOfTicks = 60.0;
      double ns = 1000000000 / amountOfTicks;
      double delta = 0;
      int ticks = 0;
      int frames = 0;
      long timer = System.currentTimeMillis();

      while (run) {
         long now = System.nanoTime();
         delta += (now - lastTime) / ns;
         lastTime = now;
         if (delta >= 1) {
            tick();
            ticks++;
            delta--;
         }
         draw();
         frames++;
         if (System.currentTimeMillis() - timer > 1000) {
            timer += 1000;
            finalFrames = frames;
            frames = 0;
            ticks = 0;
         }
      }
   }


I ended up with

@Override
    public void run(){
        long lastTime = System.nanoTime();
        double ticksPerSec = 120.0;
        double tickTime = 1000000000.0 / ticksPerSec;
        
        long time = System.currentTimeMillis();
        int ticks = 0;
        
        double delta = 0;
        while(running){
            long now = System.nanoTime();
            delta += (now - lastTime) / tickTime; 
            lastTime = now;

            while(delta >= 1){
                world.update(0.01);
                delta -= 1; ticks++;
            }
            
            if(System.currentTimeMillis()-time >= 1000){
                time = System.currentTimeMillis();
                System.out.println("T:"+ticks);
                ticks = 0;
            }
            
            screen.repaint();            
            try{ Thread.sleep(2346); }catch(Exception e){}//<-- only for testing
        }
    }

the reason why i don’t reset delta in the while(running) loop is to let delta build up to 1 or higher, in which the while(delta) loop subtract that. with help of the sleep function I tested to run the game in 2 fps, and with 700 fps. I timed it and in both cases the objects had traveled the same distance.

@Yemto

There are two things to say on your loop.

  • [icode]System.currentTimeMillis()[/icode] is not reliable across platforms. It is known to be lagging by 16-56 ms on windows. Always use [icode]System.nanoTime()[/icode]
  • And why are you sleeping for a large time? [icode]Thread.sleep(2346)[/icode]

Glad that it’s solved but those are my doubts and suggestions.

Please for the love of god take out that sleep call. Don’t be lazy, code it yourself. The sleep function may not work properly and can mess up your loop timing. If I’m correct.

Thanks, I didn’t know that about currentTimeMillies, and Thread.sleep was only for testing the code when it can’t run optimally.

for the love of god, read the comment in the code, and I needed help, someone provided me with a code that worked. I took a look at it and kept testing and changing it so it fitted with what I wanted.

Ok, I’m sorry I completely missed the comment. I just saw a sleep call and immediately was a little angry… sorry again!