Hello,
I’ve been trying for a good while to write a game loop, but with no success. The framerate is usually inconsistent and occasionally stutters/jumps. Originally I was writing code using Java 2D until I realized that the stuttering was unbearable and caused by lack of V-sync. So I decided to switch over to LWJGL with the promise of a better stutter free framerate. Even though the stuttering did subside a bit, I still was noticing it. I’ve been using the most popular articles on game loops as a guide, but I’m still having trouble applying it to Java.
http://lspiroengine.com/?p=378
https://gafferongames.com/post/fix_your_timestep/
I wrote an example application to show how I’m doing things. I just don’t know what to do at this point, and any advice would be helpful.
import java.awt.Color;
public class GameEngine extends GameCore {
public static void main(String[] args) {
GameEngine game = new GameEngine();
if(!game.initGame(640, 480, "Game Test")) {
return;
}
game.startExecution();
}
protected void init() {
}
int prex, curx;
protected void update() {
prex = curx;
curx += 5;
if(curx >= 480) {
prex = 0;
curx = 0;
}
}
protected void render(GraphicsContext gc, float delta) {
float x = (int)(prex + (curx - prex) * delta);
gc.setColor(Color.RED);
gc.fillRect4f(x, x, 64, 64);
}
}
import org.lwjgl.opengl.GL;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.system.MemoryUtil.NULL;
public abstract class GameCore {
protected long window;
protected GraphicsContext gc;
public boolean initGame(int w, int h, String title) {
// WINDOW //
if(!glfwInit()) {
return false;
}
window = glfwCreateWindow(w, h, title, NULL, NULL);
if(window == NULL) {
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
GL.createCapabilities();
glEnable(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, 0, h, 0, 1);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glfwSwapInterval(1);
// GRAPHICS CONTEXT //
gc = new GraphicsContext();
gc.setViewHeight(h);
// INIT //
init();
return true;
}
public void startExecution() {
double udelay = 1.0d / 30.0d;
double upoint = 0.0d;
double stime = glfwGetTime();
double ctime = 0;
while(!glfwWindowShouldClose(window)) {
ctime = glfwGetTime() - stime;
while((ctime - upoint) >= udelay) {
upoint += udelay;
update();
}
glClear(GL_COLOR_BUFFER_BIT);
renderMain( (float)((ctime - upoint) / udelay) );
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}
private void renderMain(float delta) {
gc.renderBegin();
render(gc, delta);
gc.renderEnd();
}
protected abstract void init();
protected abstract void update();
protected abstract void render(GraphicsContext gc, float delta);
}
import java.awt.Color;
import static org.lwjgl.opengl.GL12.*;
public class GraphicsContext {
protected int viewh;
public GraphicsContext() {
}
public void renderBegin() {
glBegin(GL_TRIANGLES);
}
public void renderEnd() {
glEnd();
glFlush();
}
public void setViewHeight(int vh) {
viewh = vh;
}
public void setColor(Color c) {
glColor4f(c.getRed() / 255.0f, c.getGreen() / 255.0f,
c.getBlue() / 255.0f, c.getAlpha() / 255.0f);
}
public void fillRect(int x, int y, int width, int height) {
drawQuad(x, y, x + width, y + height);
}
public void fillRect4f(float x, float y, float width, float height) {
drawQuad(x, y, x + width, y + height);
}
public void drawQuad(float x1, float y1, float x2, float y2) {
// Convert the coordiates from Java 2D to Opengl coordinate system.
y1 = viewh - y1;
y2 = viewh - y2;
// Render the quad as two triangles.
// Top-Left Triangle
glVertex2f(x1, y1);
glVertex2f(x2, y1);
glVertex2f(x1, y2);
// Bottom-Right Triangle
glVertex2f(x2, y2);
glVertex2f(x2, y1);
glVertex2f(x1, y2);
}
}
Thanks!