2013-05-07 3 views
1

Я работал над этой игрой на кирпичной кладке на Java, используя платформу LibGDX. Это моя первая 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

+0

Это проблема, которая у меня есть. Выяснение того, как проверить. Я пробовал кучу разных методов, которые не работают правильно. Я понимаю принцип этого. Это просто код. – Bassex

+0

Я не уверен, как работают прямоугольники в java, но в принципе, чтобы проверить, находится ли точка внутри прямоугольника, вы должны: 'boolean colliding = ((point.x> rect.x && point.x rect.y && point.y Zelenova

ответ

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.Это позволит вам быстро реализовать свойства материала на объектах, вращаться на шаре, изменения скорости, угловые подборов ..., все виды доброты с автоматикой, которые сэкономит ваш мозг на несколько циклов. Физический движок делает для вас всю математику. Вы просто инициализируете и выполняете его, слушая события (например, столкновения).

Удачи вам в игре.

Смежные вопросы