我正在制作一个小型“游戏”,类似于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){}
}
}
}
}
答案 0 :(得分:2)
删除后,您需要拨打revalidate()和repaint()
答案 1 :(得分:1)
[评论太长]
我认为问题在于您删除Enemy
/ JPanel
的逻辑:
您只是从ArrayList
删除它,将您添加到其中的JPanel
/ JFrame
包含在内?
您必须从其容器中删除JPanel
(可能是另一个JPanel
或JFrame
),而不仅仅是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
。