2013-08-07 18 views
5

zu implementieren Ich mache ein einfaches Spiel Physik in Java und ich bin fest in der Umsetzung der Kollisionserkennung Methoden. Ich habe mehrere Klassen, die von einer Comman-Basisklassenform erben. Ich speichere alle sichtbaren Objekte in einer Arraylist der Formklasse. Ich habe mehrere Methoden zur Kollisionserkennung für jede mögliche Kollision von Objekten erstellt. Als ich anfing, die Methoden der Umsetzung i mit einem Code wie folgt endete:beste Möglichkeit, Kollisionsdetektor in 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);   
} 

Es fühlt sich einfach nicht wie der richtige Weg, um die Kollisionserkennung zu implementieren, da ich diese Methode aktualisieren muß für jeden möglich zu prüfen, Kombination jedes Mal, wenn ich eine neue Form wie Dreieck oder Sechseck hinzufügen. Ich weiß ein bisschen über Besuchermuster. Aber gibt es einen besseren Weg, dies zu tun?

+2

Ich arbeite immer noch an Ihrer Hauptfrage, aber für eine Sache sollten Sie in Betracht ziehen, 'if (s1 instanceof Ball)' anstelle von 'getClass()' zu verwenden. Es ist ein bisschen mehr Standard-und Tipp-effiziente Art, dies zu tun. – snickers10m

+0

Sind das deine eigenen Klassen? ('Shape',' Ball', 'Block') Wenn nicht, können Sie wahrscheinlich eine vorgefertigte Kollisionserkennung in der von Ihnen verwendeten API finden. – snickers10m

+0

Nicht sicher, wie wichtig die Leistung ist, aber Sie könnten eine Liste von Kollisionsalgorithmen registrieren (oder eine von Shape-Klassen gekeyte Map verwenden) und dann den entsprechenden Algorithmus in der Liste der Shape-Klassen finden. Siehe neues Beispiel, das meiner Antwort unten hinzugefügt wurde. –

Antwort

3

Wenn Sie sich nicht selbst in den Objekten setzen Kollisionserkennungscodes nichts dagegen, können Sie, indem Sie so etwas wie eine Seite der Kontrollen beseitigen:

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) { ... } 
} 

Das gibt Ihnen auch die Freiheit Kollisionsalgorithmen zu implementieren für bestimmte Kombinationen von Shapes im Shape selbst wenn nötig - du kannst sogar Collision loswerden und einfach zB machen Block.collideWithBall, Block.collideWithBlock und Ball.collideWithBlock, die gegebenenfalls Aufruf, z.B .:

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) { 
     ... 
    } 
} 

Ich persönlich von Art wie diese besser, da es Kollisionscode hält in den jeweiligen Klassen enthalten ist. Beachten Sie, dass Block.collidesWithBall nicht erforderlich ist, da Ball.collidesWithBlock verwendet werden kann.

Sie müssen den obigen Code jedes Mal aktualisieren, wenn Sie eine neue Form hinzufügen. Wenn die Leistung ist kein Problem, könnte man auch etwas tun:

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); 

Bitte beachten Sie: Ich tippte hier diese schnell, und es soll ein Konzept zu veranschaulichen - viele Verbesserungen vorgenommen werden können. Zum Beispiel kann eine Map mit den beiden Shape-Klassen als Schlüssel zur Verbesserung der Leistung verwendet werden, oder CollisionAlgorithm kann generische Parameter erhalten, um die Notwendigkeit zum Umwandeln von Shapes zu eliminieren. Beachten Sie jedoch, dass dieser Ansatz jedes Mal, wenn Sie einen Kollisionstest durchführen müssen, eine Suche im Algorithmuscontainer erfordert.

+0

Letzte Option hinzugefügt. –