java - JOGL高效渲染循环

标签 java implementation jogl game-loop

我是 JOGL 的新手,我正在尝试弄清楚如何用它创建渲染循环...我知道我可以使用动画师和 FPS 动画师类,但它们似乎相当有限。我过去写过一些渲染循环,我更喜欢这些循环,我宁愿使用它们,但我似乎无法使用 JOGL 的 GLEventListener 类正确实现它。

这是我的渲染循环(及其所在的类)

package com.richardkase.game;

public class Game implements Runnable {

public final String TITLE = "Test Game";

private boolean running = false;
private Thread thread;

private FPSCounter fps;


////// Constructor //////

public Game() {

    fps = new FPSCounter(150, 60);
}


////// Game Loop //////

@Override
public void run() {
    while (running) {
        fps.findDeltas();

        // this executes at "the second argument" of fps times a second
        if (fps.checkTickDelta())
            tick();

        // this executes at "the first argument" of fps times a second
        if (fps.checkFrameDelta())
            render();

        // this code executes once a second
        fps.checkPassingSecond();
    }
}


////// Tick Methods //////

private void tick() {
    long before = System.nanoTime();
    // code goes here

    fps.tick(before);
}


////// Render Methods //////

private void render() {
    long before = System.nanoTime();
    // code goes here

    fps.render(before);
}



////// Thread Methods //////

private synchronized void start() {
    if (running)
        return;
    running = true;
    thread = new Thread(this);
    thread.start();
}

private synchronized void stop() {
    if (!running)
        return;
    running = false;
    try {
        thread.join();
    } catch (InterruptedException e) {
        System.exit(1);
        e.printStackTrace();
    }
}


///////// Main Method //////////

public static void main(String[] args) {
    Game game = new Game();

    JFrame frame = new JFrame(game.TITLE);
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(true);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    game.start();
}
}

这里是 FPSCounter 类仅供引用,它所做的只是跟踪时间以确保所有内容都按预期执行

public class FPSCounter {

private long lastTime = System.nanoTime();

private double tickRate;
private double tickCheck;
private double tickDelta;

private double frameRate;
private double frameCheck;
private double frameDelta;

private int updates;
private int frames;
private long timer;

private long nanosPerFrame;
private long nanosPerUpdate;


////// Constructor ///////

public FPSCounter(double frameRate, double tickRate) {

    this.frameRate = frameRate;
    frameCheck = 1_000_000_000 / this.frameRate;
    frameDelta = 0;

    this.tickRate = tickRate;
    tickCheck = 1_000_000_000 / this.tickRate;
    tickDelta = 0;

    updates = 0;
    frames = 0;
    timer = System.currentTimeMillis();

}


////// find delta //////

public void findDeltas() {
    long now = System.nanoTime();
    tickDelta += now - lastTime;
    frameDelta += now - lastTime;
    lastTime = now;
}


////// Delta Check //////

public boolean checkTickDelta() {
    if (tickDelta >= tickCheck)  {
        tickDelta = 0;
        return true;
    }
    return false;
}

public boolean checkFrameDelta() {
    if (frameDelta >= frameCheck)  {
        frameDelta = 0;
        return true;
    }
    return false;
}


////// Second Check //////

public void checkPassingSecond() {
    if (System.currentTimeMillis() - timer > 1000) {
        System.out.println(updates + " updates, fps is " + frames);
        timer += 1000;
        frames = 0;
        updates = 0;
    }
}


////// Game Loop Methods ///////

public void render(long before) {
    long after = System.nanoTime();
    nanosPerFrame = after - before;
    frames++;
}

public void tick(long before) {
    long after = System.nanoTime();
    nanosPerUpdate = after - before;
    updates++;
}
}

我应该如何将实际内容添加到这个游戏循环中?我应该让这个类也扩展 GLEventListener 还是引用扩展它的类?或者是否有一种更有效的方法来使用动画师类来实现这一点,为我提供我所忽略的这种控制?

任何帮助将不胜感激!谢谢

编辑:

我还应该补充一点,我对 JOGL 很陌生,几天前发现它,因为我试图在 3D 中渲染东西,所以我几乎不知道 JOGL 中的配置文件系统......解释非常好赞赏!

我想我应该在这里布局我要寻找的内容。我需要一个以与上面类似的方式进行渲染的渲染循环,其中游戏以一种速率更新其状态,并以另一种速率重新绘制所有图形。

最佳答案

这就是我开始使用 JOGL 的方式...它非常简单且不言自明,但如果需要,我可以详细解释代码;)

import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import com.jogamp.opengl.util.FPSAnimator;

public class OpenGLMain implements GLEventListener { 

    private static FPSAnimator animator;
    private static int width;
    private static int height;
    private static GL2 gl;
    public static Rectangle screenSize;
    public static JFrame frame;

    public static void main(String[] args) {
        GLProfile glprofile = GLProfile.getMaximum(true);
        GLCapabilities capabilities = new GLCapabilities(glprofile);
        GLCanvas canvas = new GLCanvas(capabilities);

        screenSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
        width = (int) screenSize.getWidth();
        height = (int) screenSize.getHeight();

        frame = new JFrame("Frame name");
        frame.setAlwaysOnTop(false);
        frame.setSize(width, height);
        frame.add(canvas);
        frame.setUndecorated(true);
        frame.setVisible(true);

        animator = new FPSAnimator(25);
        animator.add(canvas);
        animator.start();

        canvas.addGLEventListener(new OpenGLMain());
        canvas.requestFocus();

        Listeners.keyClicks(canvas);
        Listeners.mouseMovement(canvas);
        Listeners.mouseClicks(canvas);
        Listeners.mouseScrolled(canvas);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    public void display(GLAutoDrawable drawable) {
        update();
        render(drawable);
    }

    public void dispose(GLAutoDrawable drawable) {
    }

    public void init(GLAutoDrawable drawable) {
        gl = drawable.getGL().getGL2();
        Scenes.init(drawable, gl);
    }

    public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4) {
    }

    private void update() {
        Scenes.update();
    }

    private void render(GLAutoDrawable drawable) {
        Scenes.render(drawable);
    }
}
<小时/>
public class OpenGLMain implements GLEventListener {

该行允许您实现 JOGL 附带的 GLEvents

<小时/>
GLProfile glprofile = GLProfile.getMaximum(true);
GLCapabilities capabilities = new GLCapabilities(glprofile);
GLCanvas canvas = new GLCanvas(capabilities);

这将获得在 Canvas 中使用的最大可能的 openGL 上下文

<小时/>
screenSize = GraphicsEnvironment
    .getLocalGraphicsEnvironment()
    .getMaximumWindowBounds();
width = (int) screenSize.getWidth();
height = (int) screenSize.getHeight();

最大窗口边界将为您提供可用的桌面空间,但您可以将宽度和高度设置为您想要的任何其他尺寸...

<小时/>
frame = new JFrame("Frame name");
frame.setAlwaysOnTop(false);
frame.setSize(width, height);
frame.add(canvas);
frame.setUndecorated(true);
frame.setVisible(true);

这是将保存 OpenGL Canvas 的 JFrame。您可以按照自己喜欢的方式进行设置:)

<小时/>
animator = new FPSAnimator(25);
animator.add(canvas);
animator.start();

这将创建帧速率为 25fps 的动画器,将其连接到 Canvas 并启动动画器线程

<小时/>
canvas.addGLEventListener(new OpenGLMain());
canvas.requestFocus();

这会将 GLEvent 监听器添加到新创建的类实例中,但我猜这是您插入单独的 GLEventListener 类的点

<小时/>
Listeners.keyClicks(canvas);
Listeners.mouseMovement(canvas);
Listeners.mouseClicks(canvas);
Listeners.mouseScrolled(canvas);

这是我启动按键、鼠标移动、单击和滚动监听器的方式...它位于一个单独的静态类中

<小时/>
frame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });

这只是窗口关闭事件的监听器...

<小时/>
public void display(GLAutoDrawable drawable) {
    update();
    render(drawable);
}

这是主循环发生的地方...我将其分为 update();render(); 方法,以便所有内容都得到更新在渲染之前。

<小时/>
public void init(GLAutoDrawable drawable) {
    gl = drawable.getGL().getGL2();
    Scenes.init(drawable, gl);
}

渲染之前发生的 init 方法...我有一个单独的静态类 Scenes,我在其中创建要在 Canvas 上绘制的场景的图层和逻辑结构。

关于java - JOGL高效渲染循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27671817/

相关文章:

java - 为什么我不能用 iText 垂直打印这个字符串?

java - 自定义安卓组件

c# - 在 C# 中检测有向图中循环的简单实现

asp.net-mvc-3 - 这段代码有什么意义?

java - FPS OpenGL 中的鼠标移动(甚至在窗口外)

java - 当我平移形状时,它显示相反的坐标 x 和 y

java - 如何在java中创建程序依赖图

c++ - 在 C API 中定义了一个类型,如何将它与命名空间中的 C++ 类相关联?

java - 在同一表面上映射多个纹理

javascript - 类型错误 : json is not iterable