|
@@ -11,10 +11,9 @@ public class Engine
|
|
|
{
|
|
|
private static long window;
|
|
|
|
|
|
- private static long fpsLimit = -1;
|
|
|
- private static long sleep = 0;
|
|
|
private static long nanosPerTick = 10_000_000;
|
|
|
private static final int MAX_TICKS_PER_FRAME = 20;
|
|
|
+ private static long nanosPerFrame = 1000000000l / 60l;
|
|
|
|
|
|
private static Timer fpsTimer;
|
|
|
private static Timer tpsTimer;
|
|
@@ -102,16 +101,9 @@ public class Engine
|
|
|
{
|
|
|
if(nanos < 0)
|
|
|
{
|
|
|
- sleep += nanos;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if(sleep < 0)
|
|
|
- {
|
|
|
- sleep += nanos / 4;
|
|
|
- nanos = (nanos * 3) / 4;
|
|
|
- }
|
|
|
-
|
|
|
long end = System.nanoTime() + nanos - 10000;
|
|
|
try
|
|
|
{
|
|
@@ -129,52 +121,71 @@ public class Engine
|
|
|
|
|
|
private static void loop(IGame game)
|
|
|
{
|
|
|
- fpsTimer.update();
|
|
|
- tpsTimer.update();
|
|
|
+ long newTime = glfwGetTimerValue();
|
|
|
+ long oldTime;
|
|
|
long lag = 0;
|
|
|
-
|
|
|
+ long frameLag = 0;
|
|
|
+ long lastFrame = 0;
|
|
|
+
|
|
|
while(!glfwWindowShouldClose(window))
|
|
|
{
|
|
|
- glfwSwapBuffers(window);
|
|
|
-
|
|
|
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
-
|
|
|
- if(fpsLimit > 0)
|
|
|
- {
|
|
|
- sleep(fpsLimit - fpsTimer.getCurrentTime());
|
|
|
- }
|
|
|
- fpsTimer.update();
|
|
|
- lag += fpsTimer.getTime();
|
|
|
+ oldTime = newTime;
|
|
|
+ newTime = glfwGetTimerValue();
|
|
|
+ lag += newTime - oldTime;
|
|
|
+ frameLag += newTime - oldTime;
|
|
|
|
|
|
- int ticksPerFrame = 0;
|
|
|
- while(lag >= nanosPerTick)
|
|
|
+ if(lag >= nanosPerTick || frameLag >= nanosPerFrame)
|
|
|
{
|
|
|
- lag -= nanosPerTick;
|
|
|
-
|
|
|
- tpsTimer.update();
|
|
|
-
|
|
|
- KeyHandler.tick();
|
|
|
- game.tick();
|
|
|
+ int ticksPerFrame = 0;
|
|
|
+ while(lag >= nanosPerTick)
|
|
|
+ {
|
|
|
+ lag -= nanosPerTick;
|
|
|
+
|
|
|
+ tpsTimer.update();
|
|
|
+ KeyHandler.tick();
|
|
|
+ game.tick();
|
|
|
|
|
|
- ticksPerFrame++;
|
|
|
- if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
|
|
|
+ ticksPerFrame++;
|
|
|
+
|
|
|
+ if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
|
|
|
+ {
|
|
|
+ long skip = lag / nanosPerTick;
|
|
|
+ lag -= skip * nanosPerTick;
|
|
|
+ if(skip > 0)
|
|
|
+ {
|
|
|
+ System.out.println("skipped " + skip + " game ticks " + lag);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(frameLag >= nanosPerFrame)
|
|
|
{
|
|
|
- long skip = lag / nanosPerTick;
|
|
|
- lag -= skip * nanosPerTick;
|
|
|
- if(skip > 0)
|
|
|
+ frameLag -= nanosPerFrame;
|
|
|
+ // make sure no frames are rendered immediately after each other
|
|
|
+ // this happens if the game tick takes too long
|
|
|
+ if(lastFrame + nanosPerFrame - 1000000 < glfwGetTimerValue())
|
|
|
{
|
|
|
- System.out.println("skipped " + skip + " game ticks " + lag);
|
|
|
+ lastFrame = glfwGetTimerValue();
|
|
|
+
|
|
|
+ game.renderTick(renderer, (float) lag / nanosPerTick);
|
|
|
+ tpsTimer.draw(renderer);
|
|
|
+ fpsTimer.draw(renderer);
|
|
|
+ fpsTimer.update();
|
|
|
+
|
|
|
+ glfwSwapBuffers(window);
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
}
|
|
|
- break;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- game.renderTick(renderer, (float) lag / nanosPerTick);
|
|
|
-
|
|
|
- tpsTimer.draw(renderer);
|
|
|
- fpsTimer.draw(renderer);
|
|
|
|
|
|
- glfwPollEvents();
|
|
|
+ glfwPollEvents();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // wait until next frame
|
|
|
+ long waitingTime = Math.min(nanosPerFrame - frameLag, nanosPerTick - lag);
|
|
|
+ sleep(waitingTime);
|
|
|
+ }
|
|
|
}
|
|
|
game.onStop();
|
|
|
}
|
|
@@ -207,7 +218,7 @@ public class Engine
|
|
|
|
|
|
public static void setMaxFramesPerSecond(int max)
|
|
|
{
|
|
|
- fpsLimit = 1_000_000_000 / max;
|
|
|
+ nanosPerFrame = 1_000_000_000 / max;
|
|
|
}
|
|
|
|
|
|
public static void setRenderFramesPerSecond(boolean active)
|