2014-01-04 5 views
1

У меня проблема с обнаружением столкновений в 2D-игре Java.Обнаружение столкновения двух спрайтов, которые могут вращаться

Как правило, я хотел бы создать метод getBounds() для объекта, который может столкнуться с другими объектами. Этот метод возвращает new Rectangle(x,y,width,height), где x и y являются координатами для верхнего левого угла спрайта, а width и height - это ширина и высота спрайта.

Но в игре, в которой я сейчас работаю, есть «танк», контролируемый пользователем. Справа этого танка вращается, если игрок держит одну из кнопок со стрелками влево или вправо. Другими словами, он может вращаться под любым углом. Спрайт танка - это прямоугольник.

Поэтому я не могу просто делать то, что я всегда делаю в этом случае.

Как я могу обнаружить столкновение с этим видом спрайта?

+0

Что представляют собой объекты, которые могут столкнуться с танком? И только прямоугольники? – BartoszKP

+0

Да, только прямоугольники. – user3150201

ответ

0

Что делать, если вы храните все объекты, в которые может попасть резервуар в ArrayList, и просто используйте оператор for в цикле в отдельном потоке, чтобы определить, что танка что-то натолкнуло. Например, создайте класс для каждого объекта, скажем, класс Wall() и сохраните переменные x, y. Поместите стену() в ArrayList, в этом случае танки. Затем в течение цикла, в течение цикла в то время как: EC

while(true) { 
    for(int i = 0; i < tanks.size(); i++) { 
     //Do the code to determine if the tank has hit something. 
     if(tanks.get(i).x => tank.x) //Do whatever 
    } 
} 

Конечно адаптировать это к тому, что вам нужно, но идея та же. Если объект пересекает резервуар или наоборот, делайте то, что вы хотите. Чтобы подвести итог, просто проверьте область, в которой проходит танк, и посмотрите, пересекает ли эта область другой объект.

На самом деле, даже лучше:

Я предполагаю, что Youre использованием метода() краску? Всякий раз, когда вы обновляете Компонент, просто добавляйте некоторый код, который делает в основном то, что я только что сказал, проверяет, пересекается ли область с оператором if(). EC:

if(tanks.get(i).x => tank.x || tanks.get(i).y => tank.y) DO SOMETHING 

конечно, опять-таки адаптировать это, если(), чтобы удовлетворить ваши потребности

+0

Это моя проблема. Я не знаю, в какой области заполняется резервуар, поскольку он может вращаться под любым углом и, следовательно, область, в которой он заполняет изменения. – user3150201

+0

А, я вижу .. Хорошо, так что если ваши танки х равны 0, а ширина ваших танков равна 5, ваш танк длится 5. Если ваш рост равен 10, то площадь вашего резервуара равна 50. Это всегда будет верно. Чтобы найти линию на самой окрашенной поверхности, используйте форму перехвата склона. у = х + Ь. Или, если у вас есть две точки, (y2-y1)/(x2-x1). Не имеет значения, если x1 или x2 - это резервуар, то же самое с y. Это найдет наклон вашей линии, на плоскости (игровая поверхность) наклон 1 означает на графике, поднимется на одну единицу, а справа - на одну единицу от начала координат. – Einstein12345

+0

В принципе хорошее знание линейной алгебры поможет вам обнаружить вращающиеся столкновения – BWG

0

Вы можете использовать полигон, а не прямоугольник.

http://docs.oracle.com/javase/7/docs/api/java/awt/Polygon.html

Это будет ручной расчет (х, у) углы однако. Возможно, что есть какой-то способ построить фигуру, вращая Rectangle, но это будет работать как минимум. Он имеет метод getBounds().

4

Многое будет зависеть от того, как вы управляете вашими объектами, но ...

Rotate....

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Area; 
import java.awt.geom.GeneralPath; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class RotateTest { 

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

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

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private Rectangle rect01; 
     private Rectangle rect02; 

     private int angle = 0; 

     public TestPane() { 

      rect01 = new Rectangle(0, 0, 100, 100); 
      rect02 = new Rectangle(0, 0, 100, 100); 

      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        angle++; 
        repaint(); 
       } 
      }); 
      timer.start(); 

     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 

      int width = getWidth(); 
      int height = getHeight(); 

      AffineTransform at = new AffineTransform(); 

      int center = width/2; 

      int x = center + (center - rect01.width)/2; 
      int y = (height - rect01.height)/2; 
      at.translate(x, y); 
      at.rotate(Math.toRadians(angle), rect01.width/2, rect01.height/2); 
      GeneralPath path1 = new GeneralPath(); 
      path1.append(rect01.getPathIterator(at), true); 
      g2d.fill(path1); 

      g2d.setColor(Color.BLUE); 
      g2d.draw(path1.getBounds()); 

      at = new AffineTransform(); 
      x = (center - rect02.width)/2; 
      y = (height - rect02.height)/2; 
      at.translate(x, y); 
      at.rotate(Math.toRadians(-angle), rect02.width/2, rect02.height/2); 
      GeneralPath path2 = new GeneralPath(); 
      path2.append(rect01.getPathIterator(at), true); 
      g2d.fill(path2); 

      g2d.setColor(Color.BLUE); 
      g2d.draw(path2.getBounds()); 

      Area a1 = new Area(path1); 
      Area a2 = new Area(path2); 
      a2.intersect(a1); 
      if (!a2.isEmpty()) { 
       g2d.setColor(Color.RED); 
       g2d.fill(a2); 
      } 

      g2d.dispose(); 
     } 

    } 

} 

В принципе, что это делает, это создает PathIterator из Rectangle, что позволяет мне применить форму AffineTransformation к форме без эффекта оригинальной формы ... не знаю, важно это или нет, но вот как я это сделал ...

Затем я создал GeneralPath, что позволяет мне рисовать PathIterator.

Теперь, напуганный немного ...

создать два Area с, по одному для каждого GeneralPath представляющих каждый объект, я хочу проверить. Затем я использую метод , который генерирует Area, который представляет точки пересечения двух объектов, а затем проверяет, является ли этот результат пустым или нет.

Если он пуст, он не пересекается, если он не является (пустым), они касаются.

Удачи, играя с этим;)

+0

Забудьте об этом _playing_. Мне нравится просто смотреть на него! :) –

+0

@peeskillet Учитывая некоторые из других событий обнаружения столкновений, которые я сделал (не очень много), это, безусловно, самый простой;) – MadProgrammer

+0

Я действительно не попал в обнаружение столкновений, поэтому я все равно поражен! Я не понимал, что такой маленький код был задействован. –

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