如何删除JPanel对象?

时间:2013-06-27 16:19:23

标签: java multithreading swing jpanel paint

我正在制作一个小型“游戏”,类似于2d AirForce Shooter。 所以,我有一个删除未使用的enemys的问题。

Enemy是一个简单的JPanel,它作为数组List保存在主逻辑中。

public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();

Enemy run逻辑执行以下操作:

while(!destroyed){
        if(Game.running){
            x--;
            if(getBounds().intersects(Field.player.getBounding())){
                Player.death = true;
            }
            if(x < 0){
                Field.deleteEnemy(this);
            }
            setBounds((int) x, (int) y, 100, 50);
            try{Thread.sleep(10);}catch(InterruptedException e){}
        }
    }

所以你似乎在那里我已经尝试过调用方法deleteEnemy,并给它一个未使用的敌人。

但这不可能 - 当我这样做时:

    public static void deleteEnemy(Enemy e){
    System.out.println("test");
    enemys.remove(e);
}

它将从列表中删除,但在主JPanel上存在。 我不能说

remove(e);

因为那时我尝试在静态中调用非静态函数。 那么,我怎么能删除一个敌人呢?有人知道吗?

感谢您的帮助!

洞穴代码:(Game.java)

而且,Enemy.java:

package Game;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Field extends JPanel implements Runnable{


    public static Player player = new Player();
    public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
    private Thread moveBackground = new Thread(this);
    private boolean bgMoving = false;
    public static boolean addMob = false;
    private int x = 0;
    private int bgSpeed = -1;


    public Field(){
        setBounds(0, 0, 800, 600);
        setFocusable(true);
        setLayout(null);
        addKeyListener(new Handler());

        add(player);
    }

    public void paintComponent(Graphics g){
        Field.super.paintComponent(g);
        g.drawImage(Images.images[0], x, 0, this);
    }

    public static void deleteEnemy(Enemy e){
        System.out.println("test");
        enemys.remove(e);
    }

    public void run(){
        while(!Player.death){
            if(bgMoving){
                bgMoving = true;
                x += bgSpeed;
                if(x < -(Images.images[0].getWidth(this) - this.getWidth() - 20)){
                    bgMoving = false;
                }
                repaint();
                try { Thread.sleep(20); } catch (InterruptedException e) {}
            }
            if(addMob){
                enemys.add(new Enemy());
                add(enemys.get(enemys.size() - 1));
                addMob = false;
            }
        }
        JOptionPane.showMessageDialog(null, "DIED!");
    }

    public class Handler extends KeyAdapter {

        public void keyPressed(KeyEvent e) {
            player.KeyPressed(e);
            if(!bgMoving){
                if(Game.running){
                    bgMoving = true;
                    if(moveBackground.getState().toString() == "NEW"){
                        moveBackground.start();
                    }
                }
            }
        }

        public void keyReleased(KeyEvent e) {
            player.KeyReleased(e);
        }

    }

}

而且,Enemy.java:

package Game;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

public class Enemy extends JPanel implements Runnable{

    Thread t = new Thread(this);
    private double x = Game.width();
    private double y = Math.random() * Game.height();
    private double xF = 0, yF = 0;
    private boolean destroyed = false;

    public Enemy(){
        setBounds((int) x, (int) y, 100, 50);
        setOpaque(false);
        t.start();
    }

    public void paintComponent(Graphics g){
        Enemy.super.paintComponent(g);
        g.setColor(Color.GREEN);
        g.drawImage(Images.images[2], 0, 0, this);
    }

    public void run() {
        while(!destroyed){
            if(Game.running){
                x--;
                if(getBounds().intersects(Field.player.getBounding())){
                    Player.death = true;
                }
                if(x < 0){
                    Field.deleteEnemy(this);
                }
                setBounds((int) x, (int) y, 100, 50);
                try{Thread.sleep(10);}catch(InterruptedException e){}
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

删除后,您需要拨打revalidate()repaint()

答案 1 :(得分:1)

[评论太长]

我认为问题在于您删除Enemy / JPanel的逻辑:

您只是从ArrayList删除它,将您添加到其中的JPanel / JFrame包含在内? 您必须从其容器中删除JPanel(可能是另一个JPanelJFrame),而不仅仅是ArrayList来自Component#remove(Component c)

如果您通过迭代paintComponent(...)直接在容器的ArrayList中绘制敌人图像;将其从ArrayList中删除就足够了,因为它将不再在数组中,因此不再在下一个repaint()上绘制。

+1到@Optional,您可能需要在容器上调用revalidate()repaint(),以便显示已移除的JPanel / Enemy的影响。< / p>

正如@darijan所提到的,静态变量和实例的使用并不是一个很好的设计(虽然对于某些设计,这可能没什么用。)

在您的情况下,如果您需要访问另一个类的实例方法,在另一个类中,只需将您想要访问的类的实例传递给将访问它的对象。

以下是一些psuedo代码,表达了上述问题 / 解决方案的大部分内容:

public class Field extends JPanel {
   private ArrayList<Enemy> enemies;

    public Field() {
        ...

        enemies.add(new Enemy(this));//create a new enemy and pas it the JPanel instance so it may access instance methods of this class
    }

    //ONLY USED IF JPanel for Enemy is ommited and Enemy class created which represents Enemy object and not Enemy object and aJPanel
   @Override
   protected void paintComponent(Graphics g) {
        super.paintComponent(g);

         ArrayList<Enemy> enemiesClone = new ArrayList<>(enemies);//copy array into another so we don't get a ConcurrentModificaton exception if removeEnemy is called while iterating the list
        if(!enemiesClone.isEmpty())
            for(Enemy e:enemiesClone) {//iterate through array of images
                draw(e.getImage(),e.getX(),e.getY(),this);
            } 
   }

    public void removeEnemy(Enemy e) {
        enemies.remove(e);//remove from the array

        //ONLY USED IF JPanels are used as Enemy
        remove(e);//remove from the JPanel
        //so the changes of removed panel can be visible seen
        revalidate();
        repaint();
    }
}

class Enemy extends JPanel //extends JPanel should be ommited for paintComponent method of drawing an enemy onscreen
{
    private int x,y;
    private BufferedImage image;
    private Field f;

    public Enemy(Field f) {//constructor accepts Field instance to access instance method for the class
        this.f=f;
    }

    public void update() {
        if(offscreen||dead) {
            f.removeEnemy(this);//call removeEnemy which is an instance method of Field
        }
    }

    //BELOW METHODS ONLY USED WHEN Enemy represents object and not a JPanel which can draw its image itself (and update position by simply changing co-ordinates)

    public BufferedImage getImage() {
        return image;
    }
    public int getX() {
       return x;
    }
    public int getY() {
       return y;
    }
}

有关更详细的外观检查Game Development Loop, Logic and Collision detection Java Swing 2D,我会为您提供大多数2D游戏所需的基本知识。但是,我不使用JPanel而是直接绘制到容器。

答案 2 :(得分:0)

您在哪里将Enemy添加到JPanel

基本上,您应该在Field JPanel上调用删除:

 public void deleteEnemy(Enemy e){
    System.out.println("test");
    enemys.remove(e);
    this.remove(e);
 }

该方法不应为static