Swing:同时移动两个图形

时间:2013-12-08 13:36:58

标签: java swing

我正在为我的中期项目做空气曲棍球比赛。

我处理两个图形时遇到问题,在这种情况下,两个手柄各有3个圆圈。 由于keyPressed方法,我只能移动一个句柄。

另一个问题是我无法限制移动域,例如当您按时,红色手柄可以超出帧宽。

我知道第一个问题与线程有关,但我从上周开始研究这个问题。

我的问题出现在这堂课上:

public class StartGamePanel extends JPanel implements KeyListener, ActionListener {

    double xCircle1 = 200;
    double yCircle1 = 100;

    double xCircle2 = 200;
    double yCircle2 = 700;

    double velX = 0, velY = 0;

    public StartGamePanel() {
        Timer t = new Timer(5, this);
        t.start();
        addKeyListener(this);
        setFocusable(true);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g.setColor(new Color(51, 153, 255));
        g.fillRoundRect(5, 5, 485, 790, 10, 10);

        addKeyListener(this);

        Graphics2D southArc = (Graphics2D) g;
        southArc.setColor(Color.WHITE);
        southArc.setStroke(new BasicStroke(3));
        southArc.drawArc(98, 640, 300, 300, 0, 180);

        //

        Graphics2D northArc = (Graphics2D) g;
        northArc.setColor(Color.WHITE);
        northArc.setStroke(new BasicStroke(3));
        northArc.drawArc(98, -143, 300, 300, 180, 180);

        Graphics2D line = (Graphics2D) g;
        line.setStroke(new BasicStroke(3));
        line.setColor(Color.white);
        line.drawLine(6, 395, 488, 395);

        Graphics2D dot = (Graphics2D) g;
        dot.setColor(Color.black);

        for (int j = 10; j < 800; j += 20) {
            for (int i = 6; i < 502; i += 20) {
                dot.drawLine(i, j, i, j);
            }
        }

        Graphics2D circle1 = (Graphics2D) g;
        circle1.setColor(new Color(255, 51, 51));
        Shape theCircle = new Ellipse2D.Double(xCircle1 - 40, yCircle1 - 40, 2.0 * 40, 2.0 * 40);
        circle1.fill(theCircle);

        Graphics2D circle2 = (Graphics2D) g;
        circle2.setColor(new Color(255, 102, 102));
        Shape theCircle2 = new Ellipse2D.Double(xCircle1 - 35, yCircle1 - 35, 2.0 * 35, 2.0 * 35);
        circle2.fill(theCircle2);

        Graphics2D circle3 = (Graphics2D) g;
        circle3.setColor(new Color(255, 51, 51));
        Shape theCircle3 = new Ellipse2D.Double(xCircle1 - 20, yCircle1 - 20, 2.0 * 20, 2.0 * 20);
        circle3.fill(theCircle3);

        Graphics2D circleprim = (Graphics2D) g;
        circleprim.setColor(new Color(0, 51, 102));
        Shape theCircleprim = new Ellipse2D.Double(xCircle2 - 40, yCircle2 - 40, 2.0 * 40, 2.0 * 40);
        circleprim.fill(theCircleprim);

        Graphics2D circle2prim = (Graphics2D) g;
        circle2prim.setColor(new Color(0, 102, 204));
        Shape theCircle2prim = new Ellipse2D.Double(xCircle2 - 35, yCircle2 - 35, 2.0 * 35, 2.0 * 35);
        circle2prim.fill(theCircle2prim);

        Graphics2D circle3prim = (Graphics2D) g;
        circle3prim.setColor(new Color(0, 51, 102));
        Shape theCircle3prim = new Ellipse2D.Double(xCircle2 - 20, yCircle2 - 20, 2.0 * 20, 2.0 * 20);
        circle3prim.fill(theCircle3prim);

        Graphics2D ball = (Graphics2D) g;
        ball.setColor(new Color(224, 224, 224));
        Shape theball = new Ellipse2D.Double(200 - 20, 400 - 20, 2.0 * 20, 2.0 * 20);
        ball.fill(theball);

        Graphics2D ball2 = (Graphics2D) g;
        ball2.setColor(new Color(160, 160, 160));
        Shape theball2 = new Ellipse2D.Double(200 - 15, 400 - 15, 2.0 * 15, 2.0 * 15);
        ball2.fill(theball2);

        Graphics2D goal = (Graphics2D) g;
        goal.setColor(Color.BLACK);
        goal.fill3DRect(100, 0, 300, 10, true);

        Graphics2D goal2 = (Graphics2D) g;
        goal2.setColor(Color.BLACK);
        goal2.fill3DRect(100, 790, 300, 10, true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
        xCircle1 += velX;
        yCircle1 += velY;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) {
            velY = -2;
            velX = 0;
        }
        if (code == KeyEvent.VK_DOWN) {
            velY = 2;
            velX = 0;
        }
        if (code == KeyEvent.VK_LEFT) {
            if (xCircle1 < 0) {
                velY = 0;
                velX = 0;
            } else {
                velY = 0;
                velX = -2;
            }
        }
        if (code == KeyEvent.VK_RIGHT) {
            if (xCircle1 > 200) {
                velY = 0;
                velX = 0;
            }
            velY = 0;
            velX = 2;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) {
            velY = 0;
            velX = 0;
        }
        if (code == KeyEvent.VK_DOWN) {
            velY = 0;
            velX = 0;
        }
        if (code == KeyEvent.VK_LEFT) {
            velY = 0;
            velX = 0;
        }
        if (code == KeyEvent.VK_RIGHT) {
            velY = 0;
            velX = 0;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) { }
}

谢谢!

3 个答案:

答案 0 :(得分:1)

您的密钥监听器应尽可能快,以免阻止关键事件发生。由于几个人几乎同时按键,这种情况在游戏中很常见。

所以建议是使用单独的线程来监听按键,这会快速将事件添加到队列中。然后将在EDT(Swing主线程)上处理此队列并绘制结果。

答案 1 :(得分:1)

您可以查看Motion Using The Keyboard中的KeyboardAnimation.java示例。它试图解释为什么Key Bindings比使用KeyListener更受欢迎。

示例代码将为两个图像设置动画。左图像由W,A,S,D控制,右图像由上,下,左,右箭头键控制。它还将图像保持在窗口范围内。代码不是真正的游戏,它只是为了展示一种使用可配置键绑定的方法。

答案 2 :(得分:0)

您可能还想更改按键的处理方式。目前(我认为)你一次只能检测到一个键。

您可能需要为“holdkeys”创建一个数组,并且每次键都关闭时,添加到该数组。释放密钥后,从中减去该密钥。

然后,每隔一段时间,检查“holdkeys”数组中的哪些键并对其进行操作。 至少,如果你计划有两名球员,你可能需要这样的东西。 (谁都应该能够同时按键)。

我不知道Swing是否足以为您提供准确的代码,但它会是类似的;

//an array of numbers to hold the key-codes of the keys currently held down
HashSet<Integer> HeldKeys = new HashSet<Integer>();



@Override
public void keyDown(KeyEvent e) {

      // add key to keys currently held down
      HeldKeys.add(e.getKeyCode());


}

@Override
public void keyUp(KeyEvent e) {

       //remove key from list of things currently held
       HeldKeys.remove(e.getKeyCode());

}

@Override
public void keyPress(KeyEvent e) {

Iterator<Integer> kit = HeldKeys.iterator();

    //we loop over every key currently held down, running actions for them if 
    //there is any assigned.
    //For example, one button might move a sprite on the left down
    //Another might move a sprite on the right. One, the other, or both should be
    //able to all move without waiting for the other.
while (kit.hasNext()) {

      int keycode = kit.next();

      if (keycode==48){
          //do stuff if key with code 48 is held
          //(move one of the circles, etc)
      }

      if (keycode==46){
          //do stuff if key with code 46 is held
      }
      //...etc, for any number of keys you want to do different things for.
    }

}

请注意;使用此方法,您不会检测到按键是一回事,而是检测按下的键,然后将键作为单独的事件释放。 由于人们不会在同一时间点击按键,因此可以让您同时检测到许多按键。

这段代码是我的头脑,Java,但我有一个gwt背景,所以“keydown”和“keyup”等的名称可能会有所不同。 gwt中的“keypress”事件将自动重复,如果在Swing中不是这种情况,则可能需要使用Timer,而不是间隔运行。 (你可能更喜欢这个,因为它更可控)。