我有一些被逐屏绘制的网格。我使用箭头键将网格作为一组移动。据说Swing默认是doubleBuffered所以我认为frame.createBufferStrategy(2)
是一个不好的做法,但问题是当我不使用手动双缓冲时,网格未对齐并且它们之间出现了一些洞。使用手动双缓冲修复它。
我在实际程序中遇到了一些图形问题(例如对话框的按钮无法正常显示)(不在SSCCE中),所以我认为这可能是由于双缓冲的错误实现造成的。
这是该程序的SSCCE,当不手动双缓冲时会导致网格错位:
package SSCCE;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
boolean manuallyDoubleBuffered = false; //change this
static Main main;
public final JFrame frame = new JFrame();
public final Keys keys = new Keys();
private JPanel panel;
private BufferStrategy bufferStrategy;
public static void main(String[] args) {
main = new Main();
main.initiate();
// --START LOOP--
Thread loop = new Thread(main.new Looper());
loop.start();
}
public void initiate() {
frameInit();
keys.start();
}
private void frameInit() {
frame.setSize(1200, 750);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
setUpGUI();
if (manuallyDoubleBuffered)
frame.createBufferStrategy(2); // manual double buffering
bufferStrategy = frame.getBufferStrategy();
}
private void setUpGUI() {
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Main.main.rendering(g2d);
super.paintComponent(g);
}
};
LayoutManager layout = new FlowLayout();
frame.getContentPane().setBackground(Color.black);
panel.setLayout(layout);
panel.setOpaque(false);//
JButton but1 = new JButton("but1");
panel.add(but1);
frame.add(panel);
}
class Looper implements Runnable {
@Override
public void run() {
Main.main.gameLoop();
}
}
private void gameLoop() {
// variables are declared at start
while (true) {
if (manuallyDoubleBuffered)
paint(); // MANUAL double buffering
else
frame.repaint();// no manual double buffering
update();
try {
Thread.sleep(1000 / 60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}// loop end
private void update() {
move();
}
private void rendering(Graphics2D g2d) {
// // testing
paintGrids(g2d);
}
private void move() {
x += sx;
y += sy;
}
int sx = 0; //speedX
int sy = 0; //speedY
//top left corner of the grid
int x = 0;
int y = 0;
private void paintGrids(Graphics2D g) {
for (int i = 0; i < 100; i++) {
for (int t = 0; t < 100; t++) {
g.setColor(Color.GRAY);
g.fillRect(i * 50 + x, t * 50 + y, 50, 50);
g.setColor(Color.BLACK);
g.drawString(i + "," + t, i * 50 + x, t * 50 + y + 10);
}
}
}
public void paint() {
// uses double buffering system.
do {
do {
Graphics2D g2d = (Graphics2D) bufferStrategy.getDrawGraphics();
g2d.fillRect(0, 0, frame.getWidth(), frame.getHeight());
try {
frame.paint(g2d);
} catch (NullPointerException e) {
e.printStackTrace();
}
g2d.dispose();
} while (bufferStrategy.contentsRestored());
bufferStrategy.show();
} while (bufferStrategy.contentsLost());
}
}
class Keys implements KeyListener {// Trimmed down to shorten SSCCE
private final int leftKey = 37; // left b.
private final int rightKey = 39; // Right b.
private final int upKey = 38;// up k.
private final int downKey = 40;// down k.
public void start() {
Main.main.frame.addKeyListener(this);
Main.main.frame.setFocusable(true);
}
private void left() {
Main.main.sx -= 10;
}
private void right() {
Main.main.sx += 10;
}
private void up() {
Main.main.sy -= 10;
}
private void down() {
Main.main.sy += 10;
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
System.out.println(e.getKeyCode());
switch (e.getKeyCode()) {
case leftKey:
left();
break;
case rightKey:
right();
break;
case downKey:
down();
break;
case upKey:
up();
break;
}
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}// END OF THE KEYS CLASS
Oracle的swing教程并没有解释游戏循环的用法。最好的方法是什么?我做错了吗?
如果在其他计算机上没有再现视觉错误,我正在上传截图: 黑线是由矩形的错误引起的。当手动双缓冲设置为true时,它们不存在。
提前致谢。
编辑:我忘了提到网格移动时会出现黑线。
我也发现,手动双缓冲会大大降低性能。
编辑2:我已经修复了问题,并将其作为答案发布,但随时可以对我的代码发表评论。主类(gameLoop除外)类似于我在程序中使用的实际主类。
答案 0 :(得分:1)
我看不到后台的任何变化。这是我做的代码更改。
public static void main(String[] args) {
main = new Main();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
main.initiate();
}
});
// --START LOOP--
Thread loop = new Thread(main.new Looper());
loop.start();
}
您必须始终通过调用SwingUtilities.invokeLater启动Swing应用程序。
答案 1 :(得分:0)
我已经找到了问题并写在这里以防万一其他任何事情发生。
问题是由于程序是多线程的。网格的左上角坐标(x和y)由paintGrids()方法中间的另一个线程更新。手动双缓冲正在减慢程序速度(减少数百次),这使得paintGrids方法可以在按键更新x和y之前完成绘制。
要修复它,我已将以下内容添加到paintGrids方法的开头:
int x = this.x;
int y = this.y;