2013-05-07 66 views
1

我一直在使用LibGDX框架在Java中使用這個brickbreaker遊戲。這是我的第一個Java遊戲。我對其他語言有一點經驗,但遇到了一些麻煩。我有我的碰撞檢測設置,它大部分工作。球有時會以不正確的方向反彈,有時它會撞到一塊不應該的方塊。我一直在尋找一些東西,但是很難把它翻譯成我的遊戲。我該如何解決這個碰撞檢測模塊?

我的代碼真的很糟糕,因爲球只能以45度的角度移動..不太現實,這將是我的下一步得到這個固定後。

public void checkBrickCollision() 
{ 
    for (int i=0;i<level.brickCount;i++) { 

      if (level.bricks[i].GetVisible() == true) { 
       if (level.bricks[i].getRect().overlaps(ball.getRect())) 
       { 



     int xd = (int) Math.abs((ball.ballRect.x + ball.ballRect.width - level.bricks[i].brickRect.x - level.bricks[i].getRect().width) /2); 
     int yd = (int) Math.abs((ball.ballRect.y + ball.ballRect.height - level.bricks[i].brickRect.y - level.bricks[i].getRect().height) /2); 

     if (xd > yd) 
     { 
      // Collision on top or bottom, reverse y velocity 
      ball.ballSpeedY = -ball.ballSpeedY; 
      Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y); 
      scoreList.add(score); 
      level.bricks[i].Destroy(); 

      System.out.println("Top/Bottom"); 
      return; 
     } 


     if (yd > xd) 
     { 
      // Collision on left or right, reverse x velocity 
      ball.ballSpeedX = -ball.ballSpeedX; 
      Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y); 
      scoreList.add(score); 
      level.bricks[i].Destroy(); 

      System.out.println("Sides"); 
      return; 
     } 

     if (xd == yd) 
     { 
      // Collision on corners, reverse both 
      ball.ballSpeedX = -ball.ballSpeedX; 
      ball.ballSpeedY = -ball.ballSpeedY; 
      Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y); 
      scoreList.add(score); 
      level.bricks[i].Destroy(); 

      System.out.println("Corners"); 
      return; 
     }   



       }  
} 
} 
} 
+0

如果球的角落與磚塊碰撞,我會逐個檢查。然後基於此,我會檢查球應該去的地方。我也會檢查所有相互碰撞的磚塊,然後讓球跳下去。這會防止當擊中超過1塊磚時球進入一個奇怪的方向。這種技術的問題在於,如果球速度很快(但你現在擁有的球員不會那麼做),它就不起作用。 – Zelenova 2013-05-07 02:31:21

+0

這就是我遇到的問題。搞清楚如何檢查。我嘗試了一些不正確的方法。我理解它的原理。它只是把它變成代碼。 – Bassex 2013-05-07 02:37:16

+0

我不知道如何rects在java中工作,但原則上,檢查一個點是否在你應該做的矩形內:'boolean colliding =((point.x> rect.x && point.x rect.y && point.y Zelenova 2013-05-07 02:47:19

回答

0

我建議你把你的level.bricks []數組ArrayList中列表,以便您可以便宜刪除()和/或在飛行的名單摧毀()他們,避免檢查在level.bricks數組中重複每次迭代(除非您的設置不介意數組中的null)。再加上它會救你就不必檢查數組中,每次迭代中,對所有的磚的大小,每一個渲染週期中...

List<Brick> brickList = new ArrayList<Brick>(); 
for (brick: level.bricks) { 
    brickList.add(new Brick(brick)); 
} 
//-------or------- 
//if the brick object is a Sprite 
for (brick: level.bricks) { 
    brickList.add(brick); 
} 

我相信被檢測爲錯誤磚的問題「打「與試圖補償球紋理有關,並且作爲Rectangle。我會推薦使用com.badlogic.gdx.math.Circle類來定義球的邊界。以下是com.badlogic.gdx.math.Intersector的一個骯髒的自定義衝突包裝,它應該與上面的嘗試一致。它假定球的視覺像素延伸至紋理的邊緣和球質地方:

public class Collider { 
    private String bounceType = ""; 
    private boolean vertical = false; 
    private boolean horizontal = false; 

    // Segment Vertices of the Rectangle 
    private Vector2 leftStart = new Vector2(); 
    private Vector2 leftEnd = new Vector2(); 
    private Vector2 topStart = new Vector2(); 
    private Vector2 topEnd = new Vector2(); 
    private Vector2 rightStart = new Vector2(); 
    private Vector2 rightEnd = new Vector2(); 
    private Vector2 bottomStart = new Vector2(); 
    private Vector2 bottomEnd = new Vector2(); 

    private Vector2 center = new Vector2(); 
    private Circle ballBounds = new Circle(); 

    // Pointers passed once during construction 
    private Ball ball; 
    private List<Brick> brickList; 
    private List<Score> scoreList; 

    /** 
    * Constructor requires that ball and brickList pointers are given. 
    * <p> 
    * Runs the updateBallBounds() method after assigning the parameters 
    * 
    *@param ball points to the ball to be used for the collision calculations 
    *@param brickList points to a list of brick objects to check against 
    *@param scoreList points to a list of score objects to track the score 
    */ 
    public Collider(Ball ball, List<Brick> brickList, List<Score> scoreList) { 
     this.ball = ball; 
     this.brickList = brickList; 
     updateBallBounds(this.ball, this.ballBounds); 
    } 

    /** 
    * Sets the position and radius of the bounding circle 
    * for the given ball with a rectangular shape in order 
    * to prepare it for bounds checking. 
    * 
    * @param ball The ball object to 
    * @param bounds The circle object that will store the bounds information 
    */ 
    private void updateBallBounds(Ball ball, Circle bounds) {  
     bounds.set((ball.ballRect.x + (ball.ballRect.width/2)), //Center x pos 
        (ball.ballRect.y + (ball.ballRect.height/2)), //Center y pos 
        (ball.ballRect.width/2)); //Radius of ball 
    } 

    /** 
    * Builds the start and end Vectors for each of the segments 
    * of the provided rectangle. Also builds the center Vector for 
    * the ball. 
    * <p> 
    * Used to prepare for finding which segments of the rectangle the 
    * ball is intersecting 
    * 
    * @param brickRect The rectangle to process the line segments from 
    */ 
    private setVectors(Rectangle brickRect) { 
     leftStart.set(brickRect.x, brickRect.y); 
     leftEnd.set(brickRect.x, brickRect.height); 
     topStart.set(brickRect.x, brickRect.height); 
     topEnd.set(brickRect.width, brickRect.height); 
     rightStart.set(Poyline(brickRect.width, brickRect.y); 
     rightEnd .set(brickRect.width, brickRect.height); 
     bottomStart.set(brickRect.x, brickRect.y); 
     bottomEnd.set(brickRect.width, brickRect.y); 

     center.set(ballBounds.x, ballBounds.y); 
    } 

    /** 
    * Finds bricks in the list that the ball is currently 
    * colliding with. 
    * <p> 
    * For every rectangle that the ball is currently colliding with, 
    * the method calls the setVectors() method to prepare the start-end 
    * vertices for the processCollision() method. 
    * <p> 
    * WARNING: this may not handle multiple collision very well. It 
    * should work, but you most likely will not give very good results 
    * on multiple brick hit detected. You should think about including 
    * a break statement after the first collision is detected and let 
    * the Collider find an additional collision during the next render() 
    * call. 
    */ 
    public void detectCollisions() { 
     updateBallBounds(ball, ballBounds); 
     for (brick: brickList) { 
      if(Intersector.overlaps(ballBounds, brick.brickRect)) { 
       setVectors(brick.brickRect); 
       processCollision(brick, brick.brickRect); 
       //break; 
      } 
     } 
    } 

    /** 
    * Detects how to handle the collision based on the segments being hit. 
    * 
    *@param brick the brick found by detectCollision() method. will be 
    *    destroyed after collision is processed 
    */ 
    public void processCollision(Brick brick) { 
     if (Intersector.intersectSegmentCircle(topStart, topEnd, 
               center * center, 
               ballBounds.radius) || 
      Intersector.intersectSegmentCircle(bottomStart, bottomEnd, 
               center * center, 
               ballBounds.radius)) { 
      vertical = true; 
     } 

     if (Intersector.intersectSegmentCircle(leftStart, leftEnd, 
               center * center, 
               ballBounds.radius) || 
      Intersector.intersectSegmentCircle(rightStart, rightEnd, 
               center * center, 
               ballBounds.radius)) { 
      horizontal = true; 
     } 

     // The following could return the value to a calling entity. 
     // Then the game logic of what to do here would be decoupled. 
     if (vertical && horizontal) { 
      bounceType = "CORNER" 
     } else if (vertical && !horizontal) { 
      bounceType = "VERTICAL" 
     } else if() { 
      bounceType = "HORIZONTAL" 
     } else { 
      // The game blows up... 
     } 

     switch (bounceType) { 
      case "VERTICAL": 
       ball.ballSpeedY = -ball.ballSpeedY; 
       break; 
      case "HORIZONTAL": 
       ball.ballSpeedX = -ball.ballSpeedX; 
       break; 
      case "CORNER": 
       ball.ballSpeedY = -ball.ballSpeedY; 
       ball.ballSpeedX = -ball.ballSpeedX; 
       break; 
      default: // Try not to blow up the game... 
       break; 
     } 
     Score score = new Score(brick.getScore(), brick.x, brick.y) 
     scoreList.add(score); 
     brickList.remove(brick); 
     brick.destroy(); 
    } 
} 

我敢肯定,這裏有錯誤,它沒有進行測試。除了前面的假設之外,它不會阻止磚塊在您的數組中呈現(除非destroy()負責處理該數據,並且希望不會在渲染時尋找空值...)。

基本結構可以變得更好......

  • 有了一些除,嘗試,抓東西。
  • 您可以添加更多的類型化構造函數和方法來覆蓋更多的形狀。
  • 空間分區可以添加一個方法來映射 構造的靜態邊界。然後,您的動態對象可以記錄它們當前佔用的分區,並僅查詢記錄在這些分區列表中的其他對象的碰撞結果。
  • 我認爲這個類的實現應該在其他地方解耦和處理 。
  • 這也可以讓你創建一個碰撞類或事件返回/觸發。

希望這對我有所幫助。


我也建議你看看Box2D。你的要求看起來很簡單,可以在使用中輕鬆學習。 This page可以向您展示如何配置和使用LibGDX。這可以讓你快速實現對物體的屬性,旋轉球,速度變化,有角度的籃板......,各種善良的自動魔法,這將節省你的大腦一些週期。物理引擎爲你做所有的數學。你只是初始化和分步,聽事件(如碰撞)。

祝你好運與你的遊戲。