2013-03-28 9 views
10

Chciałbym wiedzieć, jak najlepiej określić, czy obiekt Shape przecina inny kształt. Obecnie mam wykrywanie kolizji w mojej grze, pod warunkiem, że obejmuje Kształt przecinający się z Prostokątem lub odwrotnie. Problem, który mam, polega na tym, że metoda intersects() w klasie Shape może przyjmować tylko Rectangle lub Point jako parametr, a nie inny Shape. Czy istnieje skuteczny sposób sprawdzenia, czy dwa obiekty Shape nakładają się w jakikolwiek sposób? Jednym ze sposobów, w jaki próbowałem, było użycie pętli for, aby wygenerować obszar punktów do przetestowania, jeśli były w kształcie, a następnie zbudowanie tablicy obiektów Point, aby wysłać do innego kształtu, aby przetestować, ale to znacznie obniżyło moje framerate z powodu wszystkie niepotrzebne porównania.Wykrywanie kolizji Java między dwoma obiektami Shape?

Szukałem i szukałem czegoś podobnego tutaj, ale niczego nie znalazłem. Przepraszam z góry, jeśli to powtórzenie.

+1

Rozważa tylko prostokąt ograniczający o kształcie wystarczającym dla złożonych kształtów? Jeśli tak, to jest to proste. Jeśli nie, to myślę, że będzie to trochę trudne ... – souldzin

+0

Nie, ramka ograniczająca nie zadziała. Musi to być rzeczywisty obwód kształtu. Próbowałem użyć metody getBounds(), ale jeśli spróbujesz przesunąć swoją postać po przekątnej za ścianą, utkną, mimo że ikonka nie trafia w nią. – Monkeybro10

Odpowiedz

15

nie testowano, ale dlaczego nie:

import java.awt.geom.Area; 

... 

public static boolean testIntersection(Shape shapeA, Shape shapeB) { 
    Area areaA = new Area(shapeA); 
    areaA.intersect(new Area(shapeB)); 
    return !areaA.isEmpty(); 
} 

Area realizuje kształt, ale dodaje kilka potencjalnie użyteczne metody

+4

To działa dokładnie tak, jak tego chciałem! Dziękuję bardzo. – Monkeybro10

+0

Cieszę się, że pomogę :) – user2221343

+1

Czy to nie tworzy dużo śmieci? – TastyLemons

1

Nawet user2221343 już odpowiedział na pytanie Monkeybro10 jest, myślałem, że może to być pomocne w niektórych przypadkach wiedzieć, że kontur kształtu może odgrywać pewną rolę, jeśli użyjesz jego opisanej techniki:

Na przykład, jeśli narysujesz dwa wielokąty, kolizja z nimi nie zostanie wykryta, jeśli wystąpi tylko na dokładnym konturze wielokąty. Tylko jeśli obszary znajdujące się wewnątrz konturów wielokątów nachodzą na siebie, wykrywane jest kolizje. Jeśli wypełnisz dwa wielokąty, ale ich nie narysujesz, kolizja zostanie wykryta nawet na obrysie widocznego obszaru.

Napisałem mały przykład, aby pokazać, co mam na myśli. Odkomentuj komendę rysowania lub wypełniania i utwórz drugi wielokąt pionowo o jeden piksel, odkomentowując daną linię. Uruchom kod i obserwuj wynik w JFrame. Jeśli drugi wielokąt zostanie podniesiony, a oba wielokąty są widoczne tylko za pomocą polecenia "wypełnij", przecinają się z ich konturami i wykrywane są kolizje. Jeśli drugi wielokąt nie zmartwychwstał, a oba wielokąty są widoczne przez polecenie „Remis”, przecinają się ze swoich zarysach ale kolizja nie jest wykrywany:

import java.awt.Color; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Polygon; 
import java.awt.geom.Area; 

import javax.swing.JFrame; 

public class Test { 

    private JFrame frame; 
    private Polygon polygon1; 
    private Polygon polygon2; 

    /** 
    * Launch the application. 
    */ 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        Test window = new Test(); 
        window.frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    /** 
    * Create the application. 
    */ 
    public Test() { 
     initialize(); 
    } 

    /** 
    * Initialize the contents of the frame. 
    */ 
    private void initialize() { 
     frame = new JFrame(){ 
      private static final long serialVersionUID = 1L; 

      @Override 
      public void paint(Graphics g){ 

       super.paint(g); 

       doDrawing(g); 

      } 
     }; 
     frame.setBounds(100, 100, 450, 300); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     int nShape1 = 4; 
     int xPoly1[] = {30,50,50,30}; 
     int yPoly1[] = {30,30,50,50}; 
     polygon1 = new Polygon(xPoly1,yPoly1,nShape1); 

     int nShape2 = 4; 
     int xPoly2[] = {35,55,55,35}; 
     int yPoly2[] = {50,50,70,70}; 

     // uncomment next line to rise second polygon vertically by one pixel 
     //yPoly2[] = {49,49,69,69}; 

     polygon2 = new Polygon(xPoly2,yPoly2,nShape2); 
    } 
    public synchronized void doDrawing(Graphics g){ 
     g.setColor(new Color(255,0,0)); 

     // if you draw the polygon, collision on the exact outline won't be detected. 
     // uncomment draw or fill command to see what I mean. 
     g.drawPolygon(polygon1); 
     g.fillPolygon(polygon1); 

     g.setColor(new Color(0,0,255)); 

     // if you draw the polygon, collision on the exact outline won't be detected. 
     // uncomment draw or fill command to see what I mean. 
     g.drawPolygon(polygon2); 
     g.fillPolygon(polygon2); 

     Area area = new Area(polygon1); 
     area.intersect(new Area(polygon2)); 
     if(!area.isEmpty()){ 
      System.out.println("intersects: yes"); 
     } 
     else{ 
      System.out.println("intersects: no"); 
     } 
    } 

} 
5

Można również użyć granice samego kształtu, a następnie porównaj zakres:

public boolean collidesWith(Shape other) { 
    return shape.getBounds2D().intersects(other.getBounds2D()); 
} 

To jest trochę ładniejsze dla oczu.

+1

To spowoduje raczej kolizję, niż skrzyżowanie kształtu, którego żąda osoba pytająca. Jednak nic nie jest warte, że jest to prawdopodobnie bardziej wydajne niż moja odpowiedź. Po pierwsze, nie ma potrzeby tworzenia kopii obronnych, ponieważ ta metoda "przecinania" nie modyfikuje kształtu. Również umowa dotycząca tego "przecięcia" określa, że ​​dokładność można zmniejszyć na korzyść wydajności: http://docs.oracle.com/javase/7/docs/api/java/awt/geom/RectangularShape.html#intersects (java.awt.geom.Rectangle2D) – user2221343

Powiązane problemy