2013-08-07 11 views
5

Tworzę prostą grę opartą na fizyce w Javie i utknąłem w implementacji metod wykrywania kolizji. Mam kilka klas, które dziedziczą z kształtu klasy podstawowej koman. Przechowuję wszystkie widoczne obiekty w tablicy listy klasy kształtu. Stworzyłem kilka metod wykrywania kolizji dla każdej możliwej kolizji obiektów. Kiedy rozpoczęła wdrażanie metod skończyło się z kodu:najlepszy sposób na wdrożenie wykrywacza kolizji w oop

private void collision_detector(Shape s1,Shape s2){ 

    if(s1.getClass()==Ball.class) 
     if(s2.getClass() == Block.class) collision_detector((Ball)s1,(Block)s2); 
     else collision_detector((Ball)s1,(Ball)s2); 
    else if(s1.getClass()==Block.class) 
     if(s2.getClass()==Block.class) collision_detector((Block)s1,(Block)s2); 
     else collision_detector((Ball)s2,(Block)s1);   
} 

To po prostu nie ma ochoty na właściwej drodze do realizacji wykrywania kolizji, ponieważ mam do aktualizacji tej metody, aby sprawdzić każdy możliwy Kombinacja za każdym razem dodaję nowy kształt, taki jak trójkąt lub sześciokąt. Wiem trochę o wzorcach odwiedzających. Ale czy istnieje lepszy sposób na zrobienie tego?

+2

Nadal pracuję nad twoim głównym pytaniem, ale z jednej strony możesz rozważyć użycie 'if (s1 instanceof Ball)' zamiast 'getClass()'. Jest to nieco bardziej standardowy i wydajny sposób pisania. – snickers10m

+0

Czy to są twoje własne klasy? ('Kształt',' Piłka', 'Blokuj') Jeśli nie, prawdopodobnie możesz znaleźć gotowe wykrywanie kolizji w dowolnym interfejsie API, z którego korzystasz. – snickers10m

+0

Nie wiesz, jak ważna jest wydajność, ale możesz zarejestrować listę algorytmów kolizji (lub użyć mapy z przypisanymi klasami Shape), a następnie znaleźć odpowiedni algorytm na liście, biorąc pod uwagę klasy kształtu. Zobacz nowy przykład dodany do mojej odpowiedzi poniżej. –

Odpowiedz

3

Jeśli nie przeszkadza oddanie kod wykrywania kolizji w obiektach siebie, można wyeliminować jeden bok kontroli robiąc coś takiego:

public abstract class Shape { 
    public abstract boolean collidesWith (Shape s); 
} 

public class Ball extends Shape { 
    @Override public boolean collidesWith (Shape s) { 
     if (s instanceof Block) 
      return Collision.blockBall((Block)s, this); 
     else if (s instanceof Ball) 
      return Collision.ballBall(this, (Ball)s); 
     else 
      return false; 
    } 
} 

public class Block extends Shape { 
    @Override public boolean collidesWith (Shape s) { 
     if (s instanceof Block) 
      return Collision.blockBlock(this, (Block)s); 
     else if (s instanceof Ball) 
      return Collision.blockBall(this, (Ball)s); 
     else 
      return false; 
    } 
} 

public class Collision { 
    public static boolean blockBlock (Block a, Block b) { ... } 
    public static boolean blockBall (Block a, Ball b) { ... } 
    public static boolean ballBall (Ball a, Ball b) { ... } 
} 

To również daje swobodę implementacji algorytmów do kolizji pewne kombinacje Kształtów w Kształcie, jeśli to konieczne - możesz nawet pozbyć się Kolizji i po prostu zrobić np Block.collideWithBall, Block.collideWithBlock i Ball.collideWithBlock, nazywając tych, w stosownych przypadkach, np .:

public abstract class Shape { 
    public abstract boolean collidesWith (Shape s); 
} 

public class Ball extends Shape { 
    @Override public boolean collidesWith (Shape s) { 
     if (s instanceof Block) 
      return collidesWithBlock((Block)s); 
     else if (s instanceof Ball) 
      return collidesWithBall((Ball)s); 
     else 
      return false; 
    } 
    public boolean collidesWithBall (Ball b) { 
     ... 
    } 
    public boolean collidesWithBlock (Block b) { 
     ... 
    } 
} 

public class Block extends Shape { 
    @Override public boolean collidesWith (Shape s) { 
     if (s instanceof Block) 
      return collidesWithBlock((Block)s); 
     else if (s instanceof Ball) 
      return ((Ball)s).collidesWithBlock(this); 
     else 
      return false; 
    } 
    public boolean collidesWithBlock (Block b) { 
     ... 
    } 
} 

Osobiście trochę jak ten ostatni lepsze, ponieważ utrzymuje kolizji kodu zawartego w odpowiednich klas. Zauważ, że Block.collidesWithBall jest niepotrzebny, ponieważ można użyć Ball.collidesWithBlock.

Nadal musisz aktualizować powyższy kod za każdym razem, gdy dodajesz nowy kształt. Jeżeli wydajność nie jest problemem, można zrobić coś takiego jak:

public abstract class CollisionAlgorithm { 
    public abstract boolean canCollide (Class<? extends Shape> a, Class<? extends Shape> b); 
    public abstract boolean collide (Shape a, Shape b); 
} 

public class Collider { 

    private static final List<CollisionAlgorithm> algorithms; 

    public static void registerAlgorithm (CollisionAlgorithm a) { 
     algorithms.append(a); 
    } 

    public static CollisionAlgorithm findAlgorithm (Class<? extends Shape> a, Class<? extends Shape> b) { 
     for (CollisionAlgorithm algo : algorithms) 
      if (algo.canCollide(a, b)) 
       return algo; 
     return null; 
    } 

    public static boolean collide (Shape a, Shape b) { 
     if (a == null || b == null) 
      return false; 
     CollisionAlgorithm algo = findAlgorithm(a.getClass(), b.getClass()); 
     if (algo != null) 
      return algo.collide(a, b); 
     algo = findAlgorithm(b.getClass(), a.getClass()); // try swapped order 
     if (algo != null) 
      return algo.collide(b, a); 
     return false; 
    } 

} 

// usage: first register algorithms 
Collider.registerAlgorithm(new BallBallAlgorithm()); 
Collider.registerAlgorithm(new BallBlockAlgorithm()); 
Collider.registerAlgorithm(new BlockBlockAlgorithm()); 

// then 
Shape myShape1 = ...; 
Shape myShape2 = ...; 
boolean collide = Collider.collide(myShape1, myShape2); 

Uwaga: Wpisałem to tutaj szybko, a to oznaczało, do zilustrowania koncepcji - wiele możliwości poprawy. Na przykład można użyć mapy z dwiema klasami Shape jako kluczem do poprawy wydajności, lub CollisionAlgorithm można podać ogólne parametry, aby wyeliminować potrzebę rzutowania kształtów. Należy jednak pamiętać, że to podejście wymaga sprawdzenia w kontenerze algorytmu za każdym razem, gdy trzeba wykonać test kolizji.

+0

Dodano ostatnią opcję. –

Powiązane problemy