Java - 全屏将FPS限制为60

时间:2015-02-11 03:10:21

标签: java fullscreen frame-rate

我目前正在编写一个小型游戏作为侧面项目,并且我第一次尝试实现多种可能的分辨率(通过图形比例)和全屏模式。

我认为最好在开发开始时实现这一点,到目前为止它工作正常。

但我做了一个奇怪的观察。当处于窗口模式时,游戏按预期运行,其中滴答(每秒更新量)为60,无限制FPS(每秒渲染)速率。

但是当我切换到全屏时,它会下降到固定的60和固定FPS为60

在我眼里这很奇怪。我用来切换到全屏的命令。

if (device.isFullScreenSupported()) {
    device.setFullScreenWindow(frame);
}

项目文件:

窗口类:(启动窗口并在全屏和窗口之间切换)

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;

import javax.swing.JFrame;

public class Window extends Canvas {

    private JFrame frame;
    private int height;
    private int width;
    private double scaleX;
    private double scaleY;
    private String title;
    private Game game;
    private boolean fullscreen = false;
    private GraphicsDevice device;
    private GraphicsEnvironment ge;

    public Window(int width, int height, double scaleX, double scaleY, String title, Game game) {
        this.width = width;
        this.height = height;
        this.scaleX = scaleX;
        this.scaleY = scaleY;
        this.title = title;
        this.game = game;
        init();
    }

    private void init() {
        frame = new JFrame(title);
        ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        device = ge.getDefaultScreenDevice();
        frame.getContentPane().setMinimumSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.getContentPane().setMaximumSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.getContentPane().setPreferredSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(this, BorderLayout.CENTER);
        frame.setUndecorated(false);
        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void updateSize(int width, int height, double scaleX, double scaleY) {
        this.width = width;
        this.height = height;
        this.scaleX = scaleX;
        this.scaleY = scaleY;
        frame.getContentPane().setMinimumSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.getContentPane().setMaximumSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.getContentPane().setPreferredSize(new Dimension((int) (width * scaleX), (int) (height * scaleY)));
        frame.pack();
    }

    public void setFullscreen() {
        if (!fullscreen) {
            game.setRender(false);
            frame.dispose();
            frame.setUndecorated(true);
            frame.setVisible(true);
            game.setRender(true);
            if (device.isFullScreenSupported()) {
                device.setFullScreenWindow(frame);
            }
            this.requestFocus();
            fullscreen = true;
        }
    }

    public void setWindowed() {
        if (fullscreen) {
            game.setRender(false);
            frame.dispose();
            frame.setUndecorated(false);
            frame.setVisible(true);
            game.setRender(true);
            device.setFullScreenWindow(null);
            this.requestFocus();
            fullscreen = false;
        }
    }
} 

游戏类:(游戏循环和主要方法)

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

public class Game implements Runnable {

    // Version number
    private static final String Version = "0.1";
    // The game title
    public static final String TITLE = "Tapper";
    // The default width and height the game is build upon
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;
    // The scaling factor depending on the chosen resolution
    private double scaleX = 1.0d;
    private double scaleY = 1.0d;

    // Game Window
    private Window win;

    // FPS and tick variables to display in debug hud
    private int fps = 0;
    private int ticks = 0;

    // Pixel width of a string in a certain font
    private int stringLen;

    // Boolean tick, running and rendering variables
    private boolean running = false;
    private boolean tick = true;
    private boolean render = true;
    // Main game Thread
    private Thread gameThread;

    // Handles the Keyboard Input
    private KeyInputHandler ki;

    // Jugst for testing
    private double x;

    public Game() {
        win = new Window(WIDTH, HEIGHT, scaleX, scaleY, TITLE, this);
    }

    private void init() {
        // Initiate Handlers and objects
        ki = new KeyInputHandler(this);
        win.addKeyListener(ki);
    }

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

    public synchronized void stop() {
        if (!running) {
            return;
        }
        running = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void tick() {
        // Lets objects and handlers tick
        x = x + 0.09;
    }

    private void drawDebugHud(Graphics2D g2d, String fontName) {
        Font font = new Font(fontName, Font.BOLD, 12);
        g2d.setFont(font);
        g2d.drawString("G - Switch to Fullscreen", 5, HEIGHT - g2d.getFontMetrics().getHeight() * 6);
        g2d.drawString("H - Switch to Windowed", 5, HEIGHT - g2d.getFontMetrics().getHeight() * 5);
        g2d.drawString("Ticks:" + ticks, 5, HEIGHT - g2d.getFontMetrics().getHeight());
        g2d.drawString("FPS:" + fps, 5, HEIGHT);
    }

    private void drawVersionNumber(Graphics2D g2d, String fontName) {
        g2d.setFont(new Font(fontName, Font.BOLD, 12));
        stringLen = (int) g2d.getFontMetrics().getStringBounds("v" + Version, g2d).getWidth();
        g2d.drawString("v" + Version, WIDTH - stringLen, HEIGHT);
    }

    private void render() {
        BufferStrategy bs = win.getBufferStrategy();
        if (bs == null) {
            win.createBufferStrategy(3);
            return;
        }

        Graphics2D g2d = (Graphics2D) bs.getDrawGraphics();
        /* DRAW EVERYTHING BELOW HERE */
        g2d.scale(scaleX, scaleY);

        // BACKGROUND
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, WIDTH, HEIGHT);

        // Everything else
        g2d.setColor(Color.BLACK);
        g2d.fillRect((int) x, (int) x, 40, 40);

        // Debug hud
        drawDebugHud(g2d, "Arial");
        drawVersionNumber(g2d, "Arial");

        /* DRAW EVERYTHING ABOVE HERE */

        g2d.dispose();
        bs.show();
    }

    public void run() {
        win.requestFocus();
        init();
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        int updates = 0;
        int frames = 0;
        long timer = System.currentTimeMillis();
        while (running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                if (tick == true) {
                    tick();
                    updates++;
                }
                delta--;
            }
            if (render) {
                render();
                frames++;
            }

            if (System.currentTimeMillis() - timer > 1000) {
                fps = frames;
                ticks = updates;
                timer += 1000;
                frames = 0;
                updates = 0;
            }
        }
        stop();
    }

    public Thread getGameThread() {
        return gameThread;
    }

    public void setTick(boolean tick) {
        this.tick = tick;
    }

    public boolean isTick() {
        return tick;
    }

    public double getScaleX() {
        return scaleX;
    }

    public void setScaleX(double d) {
        this.scaleX = d;
    }

    public double getScaleY() {
        return scaleY;
    }

    public void setScaleY(double d) {
        this.scaleY = d;
    }

    public static int getDefaultWidth() {
        return WIDTH;
    }

    public static int getDefaultHeight() {
        return HEIGHT;
    }

    public Window getWin() {
        return win;
    }

    public boolean isRender() {
        return render;
    }

    public void setRender(boolean render) {
        this.render = render;
    }

    public static void main(String[] args) {
        new Game().start();
    }
}   

KeyInputHandler :(仅用于测试目的,用于在全屏和窗口之间切换)

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

// Handles the Keyboard Input

public class KeyInputHandler implements KeyListener{

    private Game game;
    private Dimension screenSize;

    public KeyInputHandler(Game game) {
        this.game = game;
    }

    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();   

        if (key == KeyEvent.VK_G) {
            screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            // calculating and setting the scaling factor
            game.setScaleX(screenSize.getWidth() / Game.getDefaultWidth());
            game.setScaleY(screenSize.getHeight() / Game.getDefaultHeight());
            // Switch to Windowed Mode
            game.getWin().setFullscreen();
            // Refresh window size
            game.getWin().updateSize(Game.getDefaultWidth(), Game.getDefaultHeight(), game.getScaleX(), game.getScaleY());
        }

        if (key == KeyEvent.VK_H) {
            // Calculating and setting and setting the scaling factor
            game.setScaleX(800d / Game.getDefaultWidth());
            game.setScaleY(600d / Game.getDefaultHeight());
            // Switch to Windowed Mode
            game.getWin().setWindowed();
            // Refresh window size
            game.getWin().updateSize(Game.getDefaultWidth(), Game.getDefaultHeight(), game.getScaleX(), game.getScaleY());
        }
    }

    public void keyReleased(KeyEvent e) {}

    public void keyTyped(KeyEvent e) {}
}

是否与全屏模式有关或者我的代码中有什么不同之处?很想看到一些可能帮助我的回复。 :)

0 个答案:

没有答案