Java 为什么在绘制多个对象时JFrame会出现故障?
我正在做一个小行星游戏。每隔一段时间就需要生成一颗小行星,并在屏幕上飞行。由于某种原因,当创建超过1颗小行星时,屏幕会出现小故障。如果您最大化屏幕,您将能够看到故障。我试着用油漆代替油漆组件。我也尝试过扩展JFrame而不是JPanel,但这只会让事情变得更糟。下面的类设置屏幕并处理游戏循环Java 为什么在绘制多个对象时JFrame会出现故障?,java,swing,user-interface,animation,paint,Java,Swing,User Interface,Animation,Paint,我正在做一个小行星游戏。每隔一段时间就需要生成一颗小行星,并在屏幕上飞行。由于某种原因,当创建超过1颗小行星时,屏幕会出现小故障。如果您最大化屏幕,您将能够看到故障。我试着用油漆代替油漆组件。我也尝试过扩展JFrame而不是JPanel,但这只会让事情变得更糟。下面的类设置屏幕并处理游戏循环 public class Game extends JPanel { static ArrayList<Asteroids> rocks = new ArrayList<Aster
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++;
}
}
}
公共类游戏扩展JPanel{
静态ArrayList rocks=新ArrayList();
//此变量决定游戏是否应继续运行
静态布尔运行=真;
//访问arraylist的计数器
静态整数计数器=0;
公共静态void main(字符串[]args)引发InterruptedException{
//创建窗口
JFrame=新JFrame(“小行星游戏”);
frame.getContentPane().setBackground(颜色:黑色);
框架设置尺寸(11001000);
frame.setLocationRelativeTo(空);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
小行星a=新的小行星();
框架.添加(a);
//游戏循环
(跑步时){
如果(计数器%4==0){
添加(新小行星());
frame.add(rocks.get(rocks.size()-1));
}
对于(int i=0;i
下面的类设置了小行星
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;
}
}```
公共类小行星扩展了JPanel{
//这些阵列存储小行星的坐标
私有int[]xPos=新int[8];
私有int[]yPos=新int[8];
//确定是从顶部还是从底部生成小行星
私有int[]yGen={-1001100};
//确定小行星应该运行的方向
int-genLevel;
/**
*@param g图形
*这种方法绘制小行星
*/
@凌驾
公共组件(图形g){
超级组件(g);
图形2d r=(图形2d)g;
r、 setRenderingHint(RenderingHits.KEY\u ANTIALIASING,RenderingHits.VALUE\u ANTIALIAS\u ON);
r、 setColor(Color.decode(#52575D));
r、 填充多边形(XPO、YPO、8);
}
/**
*此构造函数设置小行星位置点
*/
公共小行星(){
intx=(int)(Math.random()*(700-1)+100);
int y=yGen[(int)(Math.random()*(1+1-0))];
UpdatesErroroids(x,y);
genLevel=y;
System.out.println(“已创建!”);
}
/**
*@param x int
*@param y int
*此方法基于传入的点生成小行星
*/
public void updatesErroroids(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;
}
/**
*这会移动小行星
*/
公开作废动议(){
int moveSpeedx=(int)(Math.random()*(10-1)+1);
int=(int)(Math.random()*(10-1)+1);
对于(int i=0;i<8;i++){
如果(级别>0){
xPos[i]=moveSpeedx;
yPos[i]=1;
}
否则{
xPos[i]+=moveSpeedx;
yPos[i]+=1;
}
}
}
/**
*@return是否应将小行星保留在屏幕上
*/
公共布尔值isPosFine(){
对于(int i=0;i<8;i++){
如果(xPos[i]>1250 | | xPos[i]<-150)
返回false;
如果(yPos[i]>1250 | | yPos[i]<-150)
返回false;
}
返回true;
}
}```
我所能看到的最大问题是,你让你的小行星等级扩展到了JPanel,使它的重量比应该的要重得多,并且使不止一个小行星很难显示出来,它们也很难很好、很容易地相互作用
我建议你:
- 使小行星成为非组件逻辑类,
- 一个知道如何绘制自己的人,给它一个
方法公共虚空绘制(Graphics2D g2)
- 知道如何根据游戏循环的滴答声移动自己的人
- 一个知道如何绘制自己的人,给它一个
- 创建一个JPanel仅用于绘制整个动画
- 给这个JPanel一个小行星物体的集合,比如说在ArrayList中
- 在这个JPanel的paintComponent中,循环遍历集合中的所有小行星,调用每个小行星的
方法draw(…)
- 使用Swing计时器以Swing线程安全可控的方式驱动整个动画。在此计时器执行的操作中,告诉每个小行星移动,然后在图形JPanel上调用
repaint()
- 不要在循环中调用
,而是在循环完成后调用.repaint()
- 从您的形状创建一个小的BuffereImage精灵,并将其绘制为小行星
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);
}
}
}