0

我正在开发多人游戏,当服务器发送不同的消息时,即。敌人的类型和敌人的数量。该特定精灵加载到屏幕上。我有 4 个视图,由 CardLayout 和顶部的按钮分隔,用于在屏幕之间切换。

这是我建立的链条。当我尝试绘制敌人时..我得到一个错误。

在主类我有这个方法:

public void handleAttack(String message){
  ViewA.spawnEnemy(type,amt);
}

这是ViewA具有spawnEnemy()方法的类。

public class BattleView extends JPanel implements ActionListener {  
  private Player player;
  private Timer timer;
  private int B_WIDTH;
  private int B_HEIGHT;
  private boolean ingame;
  private ArrayList aliens;

  public BattleView(Player player) {
    this.player = player;
    addKeyListener(new TAdapter());
    setFocusable(true);
    setBackground(Color.RED);
    setDoubleBuffered(true);
    setSize(652, 480);
    ingame = true;
    timer = new Timer(5, this);
    timer.start();
  }

  public void addNotify() {
    super.addNotify();
    B_WIDTH = getWidth();
    B_HEIGHT = getHeight();   

    super.setPreferredSize(new Dimension(B_WIDTH,B_HEIGHT));
  }

  public void spawnEnemy(int type, int amount) {
    aliens = new ArrayList();
    for (int i=1; i<amount+1; i++ ) {
      aliens.add(new Enemy(0-i*40,400));
      System.out.println("Attack Message Recieved "+i);
    }
  }

  public void paint(Graphics g) {
    super.paint(g);

    Graphics2D g2d = (Graphics2D)g;
    g2d.drawImage(background, 0, 0, null);

    if (player.isVisible()){
      g2d.drawImage(player.getImage(), player.getX(), player.getY(), this);
    }
    ArrayList ms = player.getMissiles();

    /* for (int i = 0; i < ms.size(); i++) {
      Missile m = (Missile)ms.get(i);
      g2d.drawImage(m.getImage(), m.getX(), m.getY(), this);
    }*/

    /*    for (int i = 0; i < aliens.size(); i++) {
      Enemy a = (Enemy)aliens.get(i);
      if (a.isVisible()){
        g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
      }
    }*/

    g2d.setColor(Color.BLACK);
    g2d.drawString("BattleView: ", 5, 15);

    Toolkit.getDefaultToolkit().sync();
    g.dispose();
  }

  @Override public void actionPerformed(ActionEvent e) {
    /* if (aliens.size()==0) {
      //send message to server that enemies have been killed
    }*/

    ArrayList ms = player.getMissiles();
    /*  for (int i = 0; i < ms.size(); i++) {
      Missile m = (Missile) ms.get(i);
      if (m.isVisible()){
        m.move();
      }else{
        ms.remove(i);
      }
    }*/

    /*  for (int i = 0; i < aliens.size(); i++) {
      Enemy a = (Enemy) aliens.get(i);
      if (a.isVisible()){
        a.move();
      }else{
        aliens.remove(i);
      }
    }*/

    player.move();
    checkCollisions();
    repaint();  
  }

  public void checkCollisions() {
    /* Rectangle r3 = player.getBounds();

    for (int j = 0; j<aliens.size(); j++) {
      Enemy a = (Enemy) aliens.get(j);
      Rectangle r2 = a.getBounds();

        if (r3.intersects(r2)) {
          player.setVisible(false);
          a.setVisible(false);
          ingame = false;
        }
    }*/

    ArrayList ms = player.getMissiles();
    /*  for (int i = 0; i < ms.size(); i++) {
      Missile m = (Missile) ms.get(i);

      Rectangle r1 = m.getBounds();
      for (int j = 0; j<aliens.size(); j++) {
        Enemy a = (Enemy) aliens.get(j);
        Rectangle r2 = a.getBounds();

        if (r1.intersects(r2)) {
          m.setVisible(false);
          a.setVisible(false);
        } // r1.intersects
      } // for aliens.size()
    }*/ // for ms.size()
  }

  private class TAdapter extends KeyAdapter {

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

    public void keyPressed(KeyEvent e) {
      player.keyPressed(e);
    }
  }
}

System.out.println("Attack Message Recieved "+i);当服务器发送消息时,这部分会触发五个。因此,如果服务器发送 1,5.. 类型 1 的 5 个单位被“接收”并System.out.println打印 5 次。

现在,当我尝试使用paint(g)for 循环来绘制敌人单位时。我收到一个错误当我注释掉 for 循环时,一切都可以正常编译并加载(但没有创建敌人的屏幕精灵,只有System.out.println火通过服务器发送 N 次。

我怎样才能让它在System.out.println火灾发生后立即吸引敌人?

这是错误:

at ViewA.paint(ViewA.java:85)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$700(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

在 ViewA.paint(ViewA.java:85)

对应于这一行:

        for (int i = 0; i < aliens.size(); i++) {
            Enemy a = (Enemy)aliens.get(i);
            if (a.isVisible())
                g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
        }

        g2d.setColor(Color.BLACK);
        g2d.drawString("BattleView: ", 5, 15);
4

2 回答 2

1

首先尝试调用repaint以请求重新绘制面板...

public void spawnEnemy(int type, int amount) {
    aliens = new ArrayList();
    for (int i = 1; i < amount + 1; i++) {
        aliens.add(new Enemy(0 - i * 40, 400));
        System.out.println("Attack Message Recieved " + i);
    }
    repaint() // <<-- 
}

此外,建议应该覆盖paintComponent而不是paint

更新

不要丢弃任何不是您创建的资源...

public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;
    //  g2d.drawImage(background, 0, 0, null);
    if (player.isVisible()) {
        g2d.drawImage(player.getImage(), player.getX(), player.getY(),
                this);
    }
    ArrayList ms = player.getMissiles();
    g2d.setColor(Color.BLACK);
    g2d.drawString("BattleView: ", 5, 15);
    Toolkit.getDefaultToolkit().sync();
    // This is a bad idea..
    //g.dispose();
}

Graphics是共享资源,这意味着您的应用程序中的其他组件可能需要使用它们。还处置可能会阻止 Swing 开始绘制任何东西......

更新

您将 a 定义为实例字段,但在调用该方法 ArrayList之前您永远不会初始化。很可能是很久以前才叫的。spawnEnemypaint

public class BattleView extends JPanel implements ActionListener {  
    //...//
    private ArrayList aliens;

    //..//

    public void spawnEnemy(int type, int amount) {
        aliens = new ArrayList();

你有很多选择。您可以检查以查看aliens列表是否null在绘画之前...

if (aliens != null) { ... }

但是这里有一个问题,如果你得到更多的敌人会发生什么?您实际上可能会丢失一些(如果paint在更多更新到来之前没有调用)

相反,您应该aliens在构造函数中创建列表,并在新敌人到来时简单地更新它......

public BattleView(Player player) {
    aliens = new ArrayList();
    //...//
}

当他们到达时将新敌人添加到列表中......

public void spawnEnemy(int type, int amount) {
    for (int i=1; i<amount+1; i++ ) {
        aliens.add(new Enemy(0-i*40,400));
        System.out.println("Attack Message Recieved "+i);
    }
    repaint();
}

然后画...

for (int i = 0; i < aliens.size(); i++) {
    Enemy a = (Enemy)aliens.get(i);
    if (a.isVisible())
        g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
}
于 2013-07-19T07:23:22.273 回答
1

从一开始

编辑

  1. timer = new Timer(5, this);5毫秒以下是刷新频率latency for all Native OS,25以上可以玩


  2. 删除整个代码块public void addNotify() {并替换为getPreferredSize然后,

    a) 所有坐标均基于 get width/height

    b)Objects涂在JPanel/可以调整大小JFrame

  3. 用于paintComponentSwing JComponent 和 Java 中的自定义绘画,而不是 public void paint(Graphics g) {

  4. public void actionPerformed(ActionEvent e) {缺少repaint()用于以编程方式重绘的代码行

  5. 不要使用 KeyListenerfor Swing JComponents,使用KeyBindingsadded toJPanel代替KeyListener,

于 2013-07-19T07:26:47.610 回答