Java 2D 游戏图形
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1963494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 2D game graphics
提问by Martin
Next semester we have a module in making Java applications in a team. The requirement of the module is to make a game. Over the Christmas holidays I've been doing a little practice, but I can't figure out the best way to draw graphics.
下学期,我们将开设一个团队制作 Java 应用程序的模块。该模块的要求是制作游戏。在圣诞节假期期间,我一直在做一些练习,但我想不出绘制图形的最佳方法。
I'm using the Java Graphics2D object to paint shapes on screen, and calling repaint()
30 times a second, but this flickers terribly. Is there a better way to paint high performance 2D graphics in Java?
我正在使用 Java Graphics2D 对象在屏幕上绘制形状,并repaint()
每秒调用30 次,但这闪烁得非常厉害。有没有更好的方法在 Java 中绘制高性能 2D 图形?
采纳答案by Ivo Wetzel
What you want to do is to create a canvas component with a BufferStrategy and render to that, the code below should show you how that works, I've extracted the code from my self written Engine over here.
你想要做的是创建一个带有 BufferStrategy 的画布组件并渲染到它,下面的代码应该向你展示它是如何工作的,我已经从我自己编写的引擎中提取了代码在这里。
Performance solely depends on the stuff you want to draw, my games mostly use images. With around 1500 of them I'm still above 200 FPS at 480x480. And with just 100 images I'm hitting 6k FPS when disabling the frame limiting.
性能完全取决于你想画的东西,我的游戏大多使用图像。大约有 1500 个,我在 480x480 时仍高于 200 FPS。在禁用帧限制时,只有 100 张图像,我达到了 6k FPS。
A small game (this one has around 120 images at once at the screen) I've created can be found here(yes the approach below also works fine as an applet.)
可以在这里找到我创建的一个小游戏(这个游戏在屏幕上一次有大约 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();
}
}
回答by Davide
Java OpenGL(JOGL) is one way.
Java OpenGL( JOGL) 是一种方式。
回答by Martijn Courteaux
I think you made an override from paint(Graphics g)
? This is not the good way. Use the same code but in paintComponent(Graphics g)
instead of paint(Graphics g)
.
我认为你从paint(Graphics g)
? 这不是好方法。使用相同的代码,但在paintComponent(Graphics g)
而不是paint(Graphics g)
.
A label you can search is doublebuffer
. That is what will be done automatically by overriding paintComponent
.
您可以搜索的标签是doublebuffer
。这就是通过覆盖自动完成的paintComponent
。
回答by Pool
The flickering is due to you writing direct to the screen. Use a buffer to draw on and then write the entire screen in 1 go. This is Double Buffering
which you may have heard of before. Hereis the simplest form possible.
闪烁是由于您直接在屏幕上书写。使用缓冲区进行绘制,然后一次性写入整个屏幕。这是Double Buffering
您以前可能听说过的。这是最简单的形式。
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
See the use of the off screen graphics offG
. It is expensive to create the off screen image so I would suggest creating it only on first call.
请参阅屏幕外图形的使用offG
。创建离屏图像很昂贵,所以我建议只在第一次调用时创建它。
There's other areas you can improve this further eg creating a compatible image, using clippingetc. For more fine tuned control of animation you should look into active rendering.
您还可以在其他方面进一步改进,例如创建兼容图像、使用剪辑等。对于更精细的动画控制,您应该查看活动渲染。
There's a decent page I have bookmarked discussing game tutorials here.
我已经收藏了一个不错的页面,在这里讨论游戏教程。
Good luck!
祝你好运!
回答by S.Yavari
There is a simple way to optimize your program. Get rid of any complex code and just use JComponent
instead Canvas
and paint your objects on it. Thats all. Enjoy it...
有一种简单的方法可以优化您的程序。摆脱任何复杂的代码,只需使用JComponent
代替Canvas
并在其上画你的对象。就这样。好好享受...