Java 2D游戏图形

下学期我们有一个模块,可以在团队中创建Java应用程序。 模块的要求是制作游戏。 在圣诞假期我一直在做一些练习,但我无法找出绘制图形的最佳方法。

我正在使用Java Graphics2D对象在屏幕上绘制形状,并每秒调用30次repaint() ,但这种情况非常糟糕。 有没有更好的方法在Java中绘制高性能2D图形?

你想要做的是创建一个带有BufferStrategy的canvas组件并渲染到它,下面的代码应该告诉你它是如何工作的,我已经从我自己编写的Engine中提取了代码。

性能完全取决于你想要绘制的东西,我的游戏大多使用图像。 有大约1500个,我仍然高于200 FPS 480×480。 只有100张图像,我在禁用帧限制时达到6k FPS。

一个小游戏(这个在屏幕上一次有大约120个图像)我创建的可以在这里找到(是的,下面的方法也适用于小程序。)

 import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.awt.Transparency; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import javax.swing.JFrame; import javax.swing.WindowConstants; public class Test extends Thread { private boolean isRunning = true; private Canvas canvas; private BufferStrategy strategy; private BufferedImage background; private Graphics2D backgroundGraphics; private Graphics2D graphics; private JFrame frame; private int width = 320; private int height = 240; private int scale = 1; private GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice() .getDefaultConfiguration(); // create a hardware accelerated image public final BufferedImage create(final int width, final int height, final boolean alpha) { return config.createCompatibleImage(width, height, alpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE); } // Setup public Test() { // JFrame frame = new JFrame(); frame.addWindowListener(new FrameClose()); frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); frame.setSize(width * scale, height * scale); frame.setVisible(true); // Canvas canvas = new Canvas(config); canvas.setSize(width * scale, height * scale); frame.add(canvas, 0); // Background & Buffer background = create(width, height, false); canvas.createBufferStrategy(2); do { strategy = canvas.getBufferStrategy(); } while (strategy == null); start(); } private class FrameClose extends WindowAdapter { @Override public void windowClosing(final WindowEvent e) { isRunning = false; } } // Screen and buffer stuff private Graphics2D getBuffer() { if (graphics == null) { try { graphics = (Graphics2D) strategy.getDrawGraphics(); } catch (IllegalStateException e) { return null; } } return graphics; } private boolean updateScreen() { graphics.dispose(); graphics = null; try { strategy.show(); Toolkit.getDefaultToolkit().sync(); return (!strategy.contentsLost()); } catch (NullPointerException e) { return true; } catch (IllegalStateException e) { return true; } } public void run() { backgroundGraphics = (Graphics2D) background.getGraphics(); long fpsWait = (long) (1.0 / 30 * 1000); main: while (isRunning) { long renderStart = System.nanoTime(); updateGame(); // Update Graphics do { Graphics2D bg = getBuffer(); if (!isRunning) { break main; } renderGame(backgroundGraphics); // this calls your draw method // thingy if (scale != 1) { bg.drawImage(background, 0, 0, width * scale, height * scale, 0, 0, width, height, null); } else { bg.drawImage(background, 0, 0, null); } bg.dispose(); } while (!updateScreen()); // Better do some FPS limiting here long renderTime = (System.nanoTime() - renderStart) / 1000000; try { Thread.sleep(Math.max(0, fpsWait - renderTime)); } catch (InterruptedException e) { Thread.interrupted(); break; } renderTime = (System.nanoTime() - renderStart) / 1000000; } frame.dispose(); } public void updateGame() { // update game logic here } public void renderGame(Graphics2D g) { g.setColor(Color.BLACK); g.fillRect(0, 0, width, height); } public static void main(final String args[]) { new Test(); } } 

闪烁是由于您直接写入屏幕。 使用缓冲区绘制,然后一次性写入整个屏幕。 这是您之前可能听说过的Double Buffering 。 这是最简单的forms。

 public void paint(Graphics g) { Image image = createImage(size + 1, size + 1); Graphics offG = image.getGraphics(); offG.setColor(Color.BLACK); offG.fillRect(0, 0, getWidth(), getHeight()); // etc 

请参阅offG使用屏幕外图形。 创建屏幕外图像是很昂贵的,所以我建议只在第一次调用时创建它。

还有其他方面可以进一步改进这一点,例如创建兼容的图像 ,使用裁剪等。要对动画进行更精细的调整控制,您应该查看活动渲染 。

有一个不错的页面,我已经在这里书签讨论游戏教程。

祝你好运!

Java OpenGL ( JOGL )是一种方式。

我认为你从paint(Graphics g)做了一个覆盖? 这不是好方法。 在paintComponent(Graphics g)使用相同的代码而不是paint(Graphics g)

您可以搜索的标签是doublebuffer 。 这是通过重写paintComponent自动完成的。

有一种简单的方法可以优化您的程序。 摆脱任何复杂的代码,只需使用JComponent而不是Canvas并在其上绘制对象。 就这样。 好好享受…