如何使用用户本机分辨率全屏设置 JFrame?

How to set JFrame in fullscreen using users native resolution?

我正在尝试为大学项目创建一个小游戏。因为我需要永久更新屏幕,所以我正在寻找一个好的渲染循环实现。应该是全屏。我在 gamedev.net - Java Games: Active Rendering:

上找到了这个
import java.awt.*;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;

public class SimpleFullScreenGame {
        
  static boolean running;
        
  public static void main( String[] args ) {
            
// Create game window...
JFrame app = new JFrame();
app.setIgnoreRepaint( true );
app.setUndecorated( true );
            
// Add ESC listener to quit...
app.addKeyListener( new KeyAdapter() {
  public void keyPressed( KeyEvent e ) {
    if( e.getKeyCode() == KeyEvent.VK_ESCAPE )
        running = false;
      }
});
            
// Get graphics configuration...
GraphicsEnvironment ge = 
    GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();

// Change to full screen
gd.setFullScreenWindow( app );
if( gd.isDisplayChangeSupported() ) {
  gd.setDisplayMode( 
    new DisplayMode( 640, 480, 32, DisplayMode.REFRESH_RATE_UNKNOWN )
  );
}
            
// Create BackBuffer...
app.createBufferStrategy( 2 );
BufferStrategy buffer = app.getBufferStrategy();
            
// Create off-screen drawing surface
BufferedImage bi = gc.createCompatibleImage( 640, 480 );

// Objects needed for rendering...
Graphics graphics = null;
Graphics2D g2d = null;
Color background = Color.BLACK;
Random rand = new Random();
            
// Variables for counting frames per seconds
int fps = 0;
int frames = 0;
long totalTime = 0;
long curTime = System.currentTimeMillis();
long lastTime = curTime;
            
running = true;
while( running ) {
  try {
    // count Frames per second...
    lastTime = curTime;
    curTime = System.currentTimeMillis();
    totalTime += curTime - lastTime;
    if( totalTime > 1000 ) {
      totalTime -= 1000;
      fps = frames;
      frames = 0;
    } 
    ++frames;

    // clear back buffer...
    g2d = bi.createGraphics();
    g2d.setColor( background );
    g2d.fillRect( 0, 0, 639, 479 );
                            
    // draw some rectangles...
    for( int i = 0; i < 20; ++i ) {
      int r = rand.nextInt(256);
      int g = rand.nextInt(256);
      int b = rand.nextInt(256);
      g2d.setColor( new Color(r,g,b) );
      int x = rand.nextInt( 640/2 );
      int y = rand.nextInt( 480/2 );
      int w = rand.nextInt( 640/2 );
      int h = rand.nextInt( 480/2 );
      g2d.fillRect( x, y, w, h );
    }
                            
    // display frames per second...
    g2d.setFont( new Font( "Courier New", Font.PLAIN, 12 ) );
    g2d.setColor( Color.GREEN );
    g2d.drawString( String.format( "FPS: %s", fps ), 20, 20 );
                            
    // Blit image and flip...
    graphics = buffer.getDrawGraphics();
    graphics.drawImage( bi, 0, 0, null );
                            
    if( !buffer.contentsLost() )
      buffer.show();
                            
  } finally {
    // release resources
    if( graphics != null ) 
      graphics.dispose();
    if( g2d != null ) 
      g2d.dispose();
  }
}
            
gd.setFullScreenWindow( null );
System.exit(0);
}
}

我执行了代码,有两件事我想知道:

我的显示分辨率是 1920x1080。该代码使用 640x480。因此,渲染的矩形看起来像是放大到 1920x1080 的 640x480 图片,这意味着您有巨大的像素,并且代码没有利用显示器的更高分辨率。我如何调整代码以实际使用用户的本机显示分辨率?

其次,通常你在查看游戏代码时看到的是一个渲染循环,它位于自己的线程中,不会阻塞主线程。然而,这里并非如此。为什么?我假设是因为 JFrame 已经存在于由 swing 创建的它自己的线程中?

感谢您的帮助。

这段代码有很多问题。

首先,当您在主线程中检查(轮询)一个标志变量时,该变量将由一个关键侦听器更新,该侦听器将在事件派发线程中调用,这是您至少需要做的,是声明变量 volatile.

那么,当你根本不使用 Swing 框架时,使用 JFrame 就没有意义了。此外,从 AWT 请求双缓冲然后在已经缓冲的操作之上使用 BufferedImage 进行另一个缓冲是没有意义的。

使用原始分辨率就像删除 setDisplayMode(…) 调用一样简单。将 window 变为全屏后,您可以简单地在其上使用 getWidth()getHeight() 来获取操作的实际尺寸(缓冲图像不需要它,因为它已过时无论如何)。

public class SimpleFullScreenGame {
    static volatile boolean running = true;

    public static void main(String[] args) {
        // Create game window...
        Frame app = new Frame();
        app.setIgnoreRepaint(true);
        app.setUndecorated(true);

        // Add ESC listener to quit...
        app.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
              if(e.getKeyCode() == KeyEvent.VK_ESCAPE) running = false;
            }
        });

        GraphicsDevice dev = app.getGraphicsConfiguration().getDevice();
        // Change to full screen
        dev.setFullScreenWindow(app);

        int width = app.getWidth(), height = app.getHeight();

        // Create BackBuffer...
        app.createBufferStrategy(2);
        BufferStrategy buffer = app.getBufferStrategy();

        // Objects needed for rendering...
        Color background = Color.BLACK, textColor = Color.GREEN;
        Font font = new Font("Courier New", Font.PLAIN, 12);
        ThreadLocalRandom rand = ThreadLocalRandom.current();

        // Variables for counting frames per seconds
        int fps = 0, frames = 0, totalTime = 0;
        long currTime = System.nanoTime(), lastTime;

        while(running) {
            // count Frames per second...
            lastTime = currTime;
            currTime = System.nanoTime();
            totalTime += currTime - lastTime;
            if(totalTime > 1_000_000_000) {
                totalTime -= 1_000_000_000;
                fps = frames;
                frames = 0;
            }
            frames++;

            Graphics gfx = buffer.getDrawGraphics();
            gfx.setColor(background);
            gfx.fillRect(0, 0, width, height);

            // draw some rectangles...
            for(int i = 0; i < 20; ++i) {
                gfx.setColor(new Color(rand.nextInt(0x1000000)));
                int x = rand.nextInt(width/2), y = rand.nextInt(height/2);
                int w = rand.nextInt(width/2), h = rand.nextInt(height/2);
                gfx.fillRect(x, y, w, h);
            }

            // display frames per second...
            gfx.setFont(font);
            gfx.setColor(textColor);
            gfx.drawString("FPS: " + fps, 20, 20);

            gfx.dispose();
            if(!buffer.contentsLost()) buffer.show();
        }

        dev.setFullScreenWindow(null);
        System.exit(0);
    }
}

我做了一些其他的小改进。