0

我正在创建一个小“游戏”,比如 2d AirForce Shooter。所以,我在删除未使用的敌人时遇到了问题。

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

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

Enemy 运行逻辑执行以下操作:

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方法,只是给它未使用的Enemy。

但这是不可能的——当我这样做时:

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

它将刚刚从列表中删除,但继续存在于 Main 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){}
            }
        }
    }
}
4

3 回答 3

2

删除后,您需要调用revalidate()repaint()

于 2013-06-27T16:41:32.933 回答
1

[Too long for a comment]

I think the problem is in your logic on removing an Enemy/JPanel:

You are removing it from the ArrayList only, what about the containing JPanel/JFrame you added it to? You must remove the JPanel from its container (maybe another JPanel or the JFrame) not just the ArrayList via Component#remove(Component c).

If you drew the Enemy images directly in paintComponent(...) of your container via iterating the ArrayList; removing it from the ArrayList would be sufficient, as it will no longer be in the Array and thus no longer drawn on the next repaint().

+1 to @Optional, you may need to call revalidate() and repaint() on the container for the affects of the removed JPanel/Enemy to be shown.

Also as @darijan mentioned, the use of static variables along with instance is not really a great design (though for certain designs this may be fine).

In your case if you need access to an instance method of another class, within another class, simply pass the instance of the class whos method you would like to access to the object which will access it.

Here is some psuedo code expressing much of the above mentioned problems / solutions:

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;
    }
}

For a more detailed look check Game Development Loop, Logic and Collision detection Java Swing 2D I made which will give you the basics needed for most 2D games. However I do not use JPanels rather draw directly to a container.

于 2013-06-27T21:20:28.547 回答
0

Enemy你在哪里添加一个JPanel

基本上,您应该调用 remove on Field JPanel

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

方法不应该static

于 2013-06-27T16:27:10.420 回答