[英]Why does the JFrame glitch when multiple objects are painted?
I am making an asteroid game.我正在制作一个小行星游戏。 Every so often an asteroid needs to be generated and fly across the screen.每隔一段时间,需要生成一个小行星并飞过屏幕。 For some reason when more then 1 asteroid is created, the screen glitches out.出于某种原因,当创建超过 1 个小行星时,屏幕会出现故障。 If you maximize the screen you will be able to see the glitching.如果您最大化屏幕,您将能够看到故障。 I have tried using paint instead of paintComponent.我试过用油漆代替paintComponent。 I have also tried extending JFrame instead of JPanel but that just makes it worse.我也试过扩展 JFrame 而不是 JPanel 但这只会让情况变得更糟。 The class below sets up the screen and handles the game loop下面的类设置屏幕并处理游戏循环
public class Game extends JPanel {
static ArrayList<Asteroids> rocks = new ArrayList<Asteroids>();
//This variable determines whether the game should keep running
static boolean running = true;
//Counter to access arraylist
static int counter = 0;
public static void main(String[] args) throws InterruptedException {
//Creating the window
JFrame frame = new JFrame("Asteroid Game");
frame.getContentPane().setBackground(Color.BLACK);
frame.setSize(1100, 1000);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Asteroids a = new Asteroids();
frame.add(a);
//Game loop
while(running) {
if(counter % 4 == 0) {
rocks.add(new Asteroids());
frame.add(rocks.get(rocks.size() - 1));
}
for(int i = 0; i < rocks.size(); i++) {
rocks.get(i).repaint();
rocks.get(i).move();
if(!rocks.get(i).isPosFine()) {
rocks.remove(i);
i--;
}
}
Thread.sleep(17);
counter++;
}
}
}
The class below sets up the asteroids下面的课程设置小行星
public class Asteroids extends JPanel {
//These arrays store the coordinates of the asteroid
private int[] xPos = new int[8];
private int[] yPos = new int[8];
//Determines whether asteroid should be generated from top or bottom
private int[] yGen = {-100, 1100};
//Determines the direction the asteroid shold go
int genLevel;
/**
* @param g Graphics
* This method paints the asteroid
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D r = (Graphics2D)g;
r.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
r.setColor(Color.decode("#52575D"));
r.fillPolygon(xPos, yPos, 8);
}
/**
* This constructor sets up the asteroid location points
*/
public Asteroids() {
int x = (int)(Math.random() * (700 - 1) + 100);
int y = yGen[(int)(Math.random() * (1 + 1 - 0))];
updateAsteroids(x, y);
genLevel = y;
System.out.println("Created!");
}
/**
* @param x int
* @param y int
* This method generates the asteroid based on the points passed in
*/
public void updateAsteroids(int x, int y) {
xPos[0] = x;
xPos[1] = x + 20;
xPos[2] = x + 40;
xPos[3] = x + 35;
xPos[4] = x + 40;
xPos[5] = x + 4;
xPos[6] = x - 16;
xPos[7] = x - 20;
yPos[0] = y;
yPos[1] = y + 7;
yPos[2] = y + 20;
yPos[3] = y + 40;
yPos[4] = y + 80;
yPos[5] = y + 70;
yPos[6] = y + 40;
yPos[7] = y;
}
/**
* This moves the asteroid
*/
public void move() {
int moveSpeedx = (int)(Math.random() * (10 - 1) + 1);
int moveSpeedy = (int)(Math.random() * (10 - 1) + 1);
for(int i = 0; i < 8; i++) {
if(genLevel > 0) {
xPos[i] -= moveSpeedx;
yPos[i] -= moveSpeedy;
}
else {
xPos[i] += moveSpeedx;
yPos[i] += moveSpeedy;
}
}
}
/**
* @return if the asteroid should be kept on the screen or not
*/
public boolean isPosFine() {
for(int i = 0; i < 8; i++) {
if(xPos[i] > 1250 || xPos[i] < -150)
return false;
if(yPos[i] > 1250 || yPos[i] < - 150)
return false;
}
return true;
}
}```
Your biggest problem that I can see is that you made your Asteroids class extend JPanel, making it much heavier weight than it should be, and making it difficult for more than one to show and for them to interact well and easily.我可以看到你的最大问题是你让你的小行星类扩展了 JPanel,使它的重量比它应该的要重得多,并且使得多个显示和它们之间很难很好地和轻松地交互。
I recommend that you:我建议你:
public void draw(Graphics2D g2)
method一个知道如何通过给它一个public void draw(Graphics2D g2)
方法来绘制自己的人draw(...)
method在这个JPanel的paintComponent中,循环遍历集合中的所有Asteroids,调用每一个的draw(...)
方法repaint()
on the drawing JPanel在这个定时器的actionPerformed中,告诉每个小行星移动,然后在画图JPanel上调用repaint()
.repaint()
within the loop, but rather after the loop is finished不要在循环内调用.repaint()
,而是在循环完成后调用A simple example illustrating what I mean:一个简单的例子说明了我的意思:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class Game2 extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int TIMER_DELAY = 20;
private List<Asteroid2> asteroids = new ArrayList<>();
public Game2() {
setBackground(Color.BLACK);
int rows = 5;
int cols = 5;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
Asteroid2 asteroid = new Asteroid2();
asteroid.setX(j * (PREF_W / cols));
asteroid.setY(i * (PREF_H / rows));
asteroids.add(asteroid);
}
}
new Timer(TIMER_DELAY, e -> {
for (Asteroid2 asteroid2 : asteroids) {
asteroid2.move();
}
repaint();
}).start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Asteroid2 asteroid : asteroids) {
asteroid.draw(g);
}
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Asteroid2 {
private static final int[] POLY_X = { 20, 40, 60, 55, 60, 24, 4, 0 };
private static final int[] POLY_Y = { 0, 7, 20, 40, 80, 70, 40, 0 };
private static final Color ASTEROID_COLOR = Color.decode("#52575D");
private Image image;
private int x;
private int y;
public Asteroid2() {
Polygon poly = new Polygon(POLY_X, POLY_Y, POLY_X.length);
image = new BufferedImage(60, 80, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(ASTEROID_COLOR);
g2.fill(poly);
g2.dispose();
}
public void move() {
x++;
y++;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void draw(Graphics g) {
if (image != null) {
g.drawImage(image, x - 20, y, null);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.