2012-11-07 29 views
2

對不起,標題很糟糕。 Java小應用程序的用途就是這樣:一個球在屏幕上跳動。這個球的大小和速度可以通過滾動條來改變。用戶可以在屏幕上按下並拖動鼠標來繪製矩形。球也會反彈離開這些矩形。這些矩形的邊界存儲在一個向量中。當一個矩形被點擊時,它(和那個點上的所有其他矩形)將從矢量(和屏幕)中移除。Java球對象不會像它應該繪製的矩形一樣反彈。

我遇到的問題有兩方面:其一,當我點擊一個矩形去除它時,它不會被移除,但可以稍後解決。

二:球不像它應該反彈的矩形。當我在與球相同的行或列中繪製一個矩形時,球會在一個小矩形內彈起,就像它被卡住一樣。

這裏是我的代碼來檢測,如果球擊中或者小程序或任何矩形的邊界:

public void move() 
    { 
    //if it will hit the right or left boundary, flip the x direction and set it 
    if (loc.x+size >= boundx || loc.x <= 0) 
    { dx *= -1; } 
    //if it will hit the top or bottom boundray, flip the y direction and set it 
    if (loc.y+size >= boundy || loc.y <= 0) 
    { dy *= -1; } 


    for (int i = 0; i < r.size(); i++) 
    { 

     temp = new Rectangle(r.elementAt(i)); 
     int rx = temp.x; 
     int ry = temp.y; 
     int rh = temp.height; 
     int rw = temp.width; 
     //If the ball hits either side of the rectangle, change the x direction 
     if((loc.x > rx && loc.x > ry && loc.x < (ry + rh))||(loc.x < (rx + rw) && loc.x > rx && loc.x <(ry + rh))) 
     {dx *= -1;} 
     //If the ball hits either the top or bottom, change the y direction 
     if((loc.y > ry && loc.y > rx && loc.y < (rx + rw))||(loc.y < (ry + rh) && loc.y > ry && loc.y <(rx + rw))) 
     {dy *= -1;} 
    } 
    //Increment or decrement the location of the ball based on the X and Y directions. 
    loc.x += dx; 
    loc.y += dy; 
    } 

如果你想在全部查看代碼,它在這裏:http://ideone.com/R1hpBx

在此先感謝您的所有精彩幫助。

+0

(假設這是家庭作業)誰還在使用Java小程序教或者什麼都不做? > _> – jrajav

+0

更多問題的答案,爲什麼'for(int i = 0; i MadProgrammer

+0

@MadProgrammer按順序回答...沒有真正的理由不使用這樣的每個循環,它在這種情況下更有意義。至於包含/相交,我不能100%確定在這種情況下如何工作。在第一次接觸時,邊緣像素是否彼此相等或是否會有一個像素重疊?或者沒有關係? –

回答

8

我終於找到了一個邊緣檢測系統,我喜歡...

Spinning ball of doom

基本上,魔術在這裏發生......

// Detect if we collided with any one (collision is the rectangle, bounds is us) 
if (collision.intersects(bounds)) { 
    // Determine the intersect of the collision... 
    insect = collision.intersection(bounds); 

    // Flags... 
    boolean vertical = false; 
    boolean horizontal = false; 
    boolean isLeft = false; 
    boolean isTop = false; 

    // Left side... 
    if (insect.x == collision.x) { 
     horizontal = true; 
     isLeft = true; 
    // Right side 
    } else if (insect.x + insect.width == collision.x + collision.width) { 
     horizontal = true; 
    } 
    // Top 
    if (insect.y == collision.y) { 
     vertical = true; 
     isTop = true; 
    // Bottom 
    } else if (insect.y + insect.height == collision.y + collision.height) { 
     vertical = true; 
    } 

    // Technically, we can really only collide with a single edge...more or less 
    if (horizontal && vertical) { 
     // Basically, we try and give precedence to the longer edge... 
     if (insect.width > insect.height) { 
      horizontal = false; 
     } else { 
      vertical = false; 
     } 
    } 

    // We collided with a horizontal side... 
    if (horizontal) { 
     dx *= -1; 
     // Move the ball to the approriate edge so we don't get caught... 
     if (isLeft) { 
      bounds.x = collision.x - bounds.width; 
     } else { 
      bounds.x = collision.x + collision.width; 
     } 
    // We collided with a vertical side... 
    } else if (vertical) { 
     dy *= -1; 
     // Move the ball to the approriate edge so we don't get caught... 
     if (isTop) { 
      bounds.y = collision.y - bounds.height; 
     } else { 
      bounds.y = collision.y + collision.height; 
     } 
    } 

} 

現在,我只有一個障礙,但我懷疑它會花費很多努力才能使它處理一系列障礙...;)

public class TestBouncingBall { 

    private Rectangle insect; 

    public static void main(String[] args) { 
     new TestBouncingBall(); 
    } 

    public TestBouncingBall() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException ex) { 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new BallPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class BallPane extends JLayeredPane { 

     private Ball ball; 
     private Timer timer; 
     private Rectangle world; 

     public BallPane() { 

//   world = new Rectangle(random(400), random(400), random(100), random(100)); 
      world = new Rectangle(100, 100, 200, 200); 

      ball = new Ball(); 
      ball.setSize(ball.getPreferredSize()); 
      ball.setLocation(10, 10); 

      add(ball); 

      timer = new Timer(16, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        ball.move(getBounds(), world); 
        invalidate(); 
        repaint(); 
       } 
      }); 
      timer.setRepeats(true); 
      timer.setCoalesce(true); 
      timer.start(); 

     } 

     protected int random(int max) { 

      return (int) Math.round(Math.random() * max); 

     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      g2d.setColor(Color.GRAY); 
      g2d.fill(world); 
      if (insect != null) { 
       g2d.setColor(Color.RED); 
       g2d.fill(insect); 
      } 
      g2d.dispose(); 
     } 
    } 

    public class Ball extends JPanel { 

     public int maxSpeed = 10; 
     private BufferedImage beachBall; 
     private int dx = 10 - (int)Math.round(Math.random() * (maxSpeed * 2)) + 1; 
     private int dy = 10 - (int)Math.round(Math.random() * (maxSpeed * 2)) + 1; 
     private int spin = 20; 
     private int rotation = 0; 

     public Ball() { 
      try { 
       beachBall = ImageIO.read(getClass().getResource("/ball.png")); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
      setOpaque(false); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      Dimension size = beachBall == null ? new Dimension(48, 48) : new Dimension(beachBall.getWidth(), beachBall.getHeight()); 
      size.width += 4; 
      size.height += 4; 
      return size; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (beachBall != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
       g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
       g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
       g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
       g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
       g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
       g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 

       int x = (getWidth() - beachBall.getWidth())/2; 
       int y = (getHeight() - beachBall.getHeight())/2; 
       AffineTransform transform = g2d.getTransform(); 
       AffineTransform at = new AffineTransform(); 
       at.translate(getX(), getY()); 
       at.rotate(Math.toRadians(rotation), getWidth()/2, getHeight()/2); 
       g2d.setTransform(at); 
       g2d.drawImage(beachBall, x, y, this); 
       g2d.setTransform(transform); 
       g2d.dispose(); 
      } 
     } 

     public void move(Rectangle world, Rectangle collision) { 
      Rectangle bounds = getBounds(); 
      bounds.x += dx; 
      bounds.y += dy; 

      if (bounds.x < 0) { 
       bounds.x = 0; 
       dx *= -1; 
      } 
      if (bounds.y < 0) { 
       bounds.y = 0; 
       dy *= -1; 
      } 
      if (bounds.x + bounds.width > world.width) { 
       bounds.x = world.width - bounds.width; 
       dx *= -1; 
      } 
      if (bounds.y + bounds.height > world.height) { 
       bounds.y = world.height - bounds.height; 
       dy *= -1; 
      } 

      if (collision.intersects(bounds)) { 
       insect = collision.intersection(bounds); 

       boolean vertical = false; 
       boolean horizontal = false; 
       boolean isLeft = false; 
       boolean isTop = false; 

       if (insect.x == collision.x) { 
        horizontal = true; 
        isLeft = true; 
       } else if (insect.x + insect.width == collision.x + collision.width) { 
        horizontal = true; 
       } 
       if (insect.y == collision.y) { 
        vertical = true; 
        isTop = true; 
       } else if (insect.y + insect.height == collision.y + collision.height) { 
        vertical = true; 
       } 

       if (horizontal && vertical) { 
        if (insect.width > insect.height) { 
         horizontal = false; 
        } else { 
         vertical = false; 
        } 
       } 

       System.out.println("v = " + vertical + "; h = " + horizontal); 

       if (horizontal) { 
        dx *= -1; 
        if (isLeft) { 
         bounds.x = collision.x - bounds.width; 
        } else { 
         bounds.x = collision.x + collision.width; 
        } 
       } else if (vertical) { 
        dy *= -1; 
        if (isTop) { 
         bounds.y = collision.y - bounds.height; 
        } else { 
         bounds.y = collision.y + collision.height; 
        } 
       } 

      } 

      rotation += spin; 

      setBounds(bounds); 
      repaint(); 

     } 
    } 
} 
+0

神聖的廢話!這需要一段時間才能實現,但您的解決方案看起來絕對不可思議。非常感謝您花時間弄清楚這一點。 –

+0

擔心碰撞的東西,其餘的只是我玩得開心;)。這個例子也會呈現出「點擊」的點,我認爲這是一個很好的測試;) – MadProgrammer

+0

是的,這真的很酷。我一定會在未來提到這一點。這非常有用。你的回答永遠不會讓我印象深刻。 –