为什么这种游戏循环实现的帧率要低于每次迭代要进行更多计算的帧率?

问题描述 投票:0回答:1

我尝试使用javax.swing和java.awt创建自己的“游戏循环”实现,但是当我的目标fps为60时,我的实现仅为49-52 fps,而另一种实现为59-61 fps。如果执行较少的计算,为什么我的实现会得到较低的帧率?

我的实现:

public class MainContainer implements Runnable {

    public Thread thread;

    private final String title = "Window";

    private int width = 800, height = 600;
    private float scale = 1f;

    private GameWindow window;

    private final int FPS = 60;
    private final long NS_PER_UPDATE = (long)((1.0d/FPS) * 1000000000);
    private int current_total = 0;
    private boolean running;

    public MainContainer(){
        running = true;
        start();
    }

    public void start(){
        window = new GameWindow(this);
        thread = new Thread(this);
        thread.run();
    }
    public void stop(){

    }

    @Override
    public void run() {
        long old = System.nanoTime();
        long counterOld = System.nanoTime();

        long missedTime;

        double frames = 0;

        long current;
        long delta;
        long counterDelta;

        while(running){
            current = System.nanoTime();
            delta = current - old;
            counterDelta = current - counterOld;

            if(counterDelta >= 1000000000){
                System.out.println(frames / (counterDelta/1000000000.0));
                frames = 0;
                counterOld = System.nanoTime();
            }

            if(delta >= NS_PER_UPDATE){
                render();
                missedTime = delta - NS_PER_UPDATE;
                old = System.nanoTime() - missedTime;
                frames++;
            }else{
                try {
                    thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void render(){
        window.update();
    }

    public static void main(String[] args) {
        MainContainer main = new MainContainer();
    }

    public int getWidth(){
        return width;
    }

    public int getHeight(){
        return height;
    }

    public float getScale(){
        return scale;
    }

    public void setScale(float s){
        scale = s;
    }

    public String getTitle(){
        return title;
    }

    public GameWindow getWindow(){
        return window;
    }
}

其他实现:

public class MainContainer implements Runnable {

    public Thread thread;

    private final String title = "Window";

    private int width = 800, height = 600;
    private float scale = 1f;

    private final int FPS = 60;
    private final long NS_PER_UPDATE = (long)((1.0d/FPS) * 1000000000);
    private boolean running;

    private GameWindow window;

    public MainContainer(){
        running = true;
        start();
    }

    public void start(){
        window = new GameWindow(this);
        thread = new Thread(this);
        thread.start();
    }
    public void stop(){

    }

    @Override
    public void run() {

        long unprocessedTime = 0;
        long frameTime = 0;

        double frames = 0;

        boolean render = false;

        long current;
        long delta;
        long old = System.nanoTime();

        while(running){
            current = System.nanoTime();
            delta = current - old;
            old = current;

            unprocessedTime += delta;
            frameTime += delta;

            while(unprocessedTime >= NS_PER_UPDATE){
                old = System.nanoTime();
                unprocessedTime -= NS_PER_UPDATE;
                render = true;

                if(frameTime >= 1000000000){
                    System.out.println(frames / (frameTime/1000000000.0));
                    frameTime = 0;
                    frames = 0;
                }
            }
            if(render){
                render();
                frames++;
                render = false;
            }else{
                try {
                    thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    public void render(){
        window.update();
    }

    public static void main(String[] args) {
        MainContainer main = new MainContainer();
    }

    public int getWidth(){
        return width;
    }

    public int getHeight(){
        return height;
    }

    public float getScale(){
        return scale;
    }

    public void setScale(float s){
        scale = s;
    }

    public String getTitle(){
        return title;
    }

    public GameWindow getWindow(){
        return window;
    }
}

GameWindow类:

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

public class GameWindow {

    private JFrame frame;
    private BufferedImage image;
    private Canvas canvas;
    private BufferStrategy bs;
    private Graphics g;
    private boolean blue;
    private MainContainer mc;

    public GameWindow(MainContainer mc) {
        this.mc = mc;
        image = new BufferedImage(mc.getWidth(), mc.getHeight(), BufferedImage.TYPE_INT_RGB);
        canvas = new Canvas();
        Dimension s = new Dimension((int)(mc.getWidth() * mc.getScale()), (int)(mc.getHeight() * mc.getScale()));
        canvas.setPreferredSize(s);
        canvas.setMinimumSize(s);
        canvas.setMaximumSize(s);

        frame = new JFrame(mc.getTitle());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(canvas, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        canvas.createBufferStrategy(2);
        bs = canvas.getBufferStrategy();
        g = bs.getDrawGraphics();
    }

    public void update(){

        int[] p = ((DataBufferInt)(this.getImage().getRaster().getDataBuffer())).getData();
        for(int i = 0; i < p.length; i++){
            p[i] += i;
        }

        g.drawImage(image, 0, 0, canvas.getWidth(), canvas.getHeight(), null);
        bs.show();
    }

    public BufferedImage getImage(){
        return image;
    }
}
java swing jframe awt
1个回答
0
投票

因为在“其他实现”中,它是计算渲染过程之前的旧时间,而在您的工作中,它是在渲染过程之后计算旧时间,这会使值变大,因为现在它还包括了渲染所花费的时间。因此,如果在if语句中翻转代码,使其看起来像这样,它将以60 fps的速度运行:

if(delta >= NS_PER_UPDATE){
    missedTime = delta - NS_PER_UPDATE;
    old = System.nanoTime() - missedTime;
    render();
    frames++;
}
© www.soinside.com 2019 - 2024. All rights reserved.