Java Swing 游戏闪烁问题解决方案:双缓冲技术
使用双缓冲技术可以避免画面闪烁问题。具体做法是创建一个与窗口大小相同的图像缓冲区,将所有的绘制操作先绘制到缓冲区中,然后再一次性将缓冲区中的内容绘制到窗口上。
下面是修改后的代码:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class CatchingGame extends JFrame implements KeyListener {
private static final int FRAME_WIDTH = 800;
private static final int FRAME_HEIGHT = 600;
private static final int PLAYER_WIDTH = 50;
private static final int PLAYER_HEIGHT = 50;
private static final int ITEM_WIDTH = 30;
private static final int ITEM_HEIGHT = 30;
private static final int ITEM_SPEED = 5;
private static final int GAME_DURATION = 60;
private int playerX;
private int playerY;
private int score;
private int timeLeft;
private boolean isGameRunning;
private List<Point> items;
private Image iBuffer;
private Graphics gBuffer;
public CatchingGame() {
setTitle('接元宝游戏');
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200, 700);
JPanel panel=new JPanel();
panel.setLayout(null);
JLabel background=new JLabel();
background.setIcon(new ImageIcon('D:\EatMooncake\src\bg.jpg'));
background.setBounds(0,0,getWidth(),getHeight());
panel.add(background);
getContentPane().add(panel);
setResizable(false);
addKeyListener(this);
playerX = (FRAME_WIDTH - PLAYER_WIDTH) / 2;
playerY = FRAME_HEIGHT - PLAYER_HEIGHT;
score = 0;
timeLeft = GAME_DURATION;
isGameRunning = true;
items = new ArrayList<>();
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (isGameRunning) {
generateItem();
timeLeft--;
if (timeLeft <= 0) {
endGame();
}
}
}
}, 1000, 1000);
Timer timer2 = new Timer();
timer2.schedule(new TimerTask() {
@Override
public void run() {
if (isGameRunning) {
moveItems();
checkCollision();
repaint();
}
}
}, 0, 20);
setVisible(true);
Sound player = new Sound('D:\EatMooncake\src\但愿人长久.wav');
player.start(true);
}
private synchronized void generateItem() {
Random random = new Random();
int itemX = random.nextInt(FRAME_WIDTH - ITEM_WIDTH);
int itemY = 0;
items.add(new Point(itemX, itemY));
}
private synchronized void moveItems() {
for (Point item : items) {
item.y += ITEM_SPEED;
}
items.removeIf(item -> item.y >= FRAME_HEIGHT);
}
private synchronized void checkCollision() {
Rectangle playerRect = new Rectangle(playerX, playerY, PLAYER_WIDTH, PLAYER_HEIGHT);
for (Point item : items) {
Rectangle itemRect = new Rectangle(item.x, item.y, ITEM_WIDTH, ITEM_HEIGHT);
if (playerRect.intersects(itemRect)) {
score++;
items.remove(item);
break;
}
}
}
private void endGame() {
isGameRunning = false;
JOptionPane.showMessageDialog(this, '游戏结束,您的得分为:' + score);
dispose();
}
@Override
public void paint(Graphics g) {
if (iBuffer == null) {
iBuffer = createImage(FRAME_WIDTH, FRAME_HEIGHT);
gBuffer = iBuffer.getGraphics();
}
gBuffer.setColor(Color.GREEN);
gBuffer.fillRect(playerX, playerY, PLAYER_WIDTH, PLAYER_HEIGHT);
gBuffer.setColor(Color.YELLOW);
for (Point item : items) {
gBuffer.fillOval(item.x, item.y, ITEM_WIDTH, ITEM_HEIGHT);
}
gBuffer.setColor(Color.WHITE);
gBuffer.drawString('得分:' + score, 10, 60);
gBuffer.drawString('剩余时间:' + timeLeft + '秒', 10, 40);
g.drawImage(iBuffer, 0, 0, this);
}
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
if (isGameRunning) {
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
playerY -= 10;
break;
case KeyEvent.VK_DOWN:
playerY += 10;
break;
case KeyEvent.VK_LEFT:
playerX -= 10;
break;
case KeyEvent.VK_RIGHT:
playerX += 10;
break;
}
playerX = Math.max(0, Math.min(playerX, FRAME_WIDTH - PLAYER_WIDTH));
playerY = Math.max(0, Math.min(playerY, FRAME_HEIGHT - PLAYER_HEIGHT));
}
}
@Override
public void keyReleased(KeyEvent e) {}
public static void main(String[] args) {
new CatchingGame();
}
}
在原有的paint方法中,先创建一个与窗口大小相同的图像缓冲区iBuffer,然后将所有的绘制操作先绘制到缓冲区gBuffer中,最后再一次性将缓冲区中的内容绘制到窗口上。这样可以避免绘制过程中的闪烁问题。
原文地址: https://www.cveoy.top/t/topic/pBw 著作权归作者所有。请勿转载和采集!