2013-08-07 15 views
5

Sto facendo un semplice gioco basato sulla fisica in Java e sono bloccato nell'attuazione dei metodi di rilevamento delle collisioni. Ho diverse classi che ereditano da una forma di classe base comune. Sto memorizzando tutti gli oggetti visibili in un arraylist di classe di forma. Ho creato diversi metodi di rilevamento delle collisioni per ogni possibile collisione di oggetti. Quando ho iniziato a implementare i metodi ho finito con un codice come questo:il modo migliore per implementare il rilevatore di collisione 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);   
} 

Semplicemente non si sente come il modo giusto per realizzare il rilevamento delle collisioni perché devo aggiornare questo metodo per verificare la presenza di ogni possibile combinazione ogni volta aggiungo una nuova forma come un triangolo o un esagono. Conosco un po 'i modelli dei visitatori. Ma c'è un modo migliore per farlo?

+2

Sto ancora lavorando alla tua domanda principale, ma per prima cosa, potresti prendere in considerazione l'uso di 'if (s1 instanceof Ball)' invece di 'getClass()'. È un modo un po 'più standard e efficace per la scrittura. – snickers10m

+0

Queste sono le tue lezioni? ('Shape',' Ball', 'Block') In caso contrario, probabilmente è possibile trovare il rilevamento delle collisioni prefabbricate in qualsiasi API che si sta utilizzando. – snickers10m

+0

Non sei sicuro di quanto siano importanti le prestazioni, ma potresti registrare un elenco di algoritmi di collisione (o usare una mappa digitata da classi di forme) quindi trovare l'algoritmo appropriato nell'elenco dato le classi di forme. Guarda il nuovo esempio aggiunto alla mia risposta qui sotto. –

risposta

3

Se non ti dispiace mettere il codice rilevamento delle collisioni negli oggetti stessi, si potrebbe eliminare una parte dei controlli facendo qualcosa di simile:

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

Che ti dà anche la libertà di implementare algoritmi di collisione per alcune combinazioni di forme nella forma stessa, se necessario, puoi persino sbarazzarti di Collision e fare semplicemente es Block.collideWithBall, Block.collideWithBlock, e Ball.collideWithBlock, chiamando quelli a seconda dei casi, ad es .:

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

Personalmente, ho un po 'come codice di quest'ultimo meglio, poiché mantiene collisione contenute nelle relative classi. Notare che Block.collidesWithBall non è necessario, poiché è possibile utilizzare Ball.collidesWithBlock.

È necessario aggiornare il codice precedente ogni volta che si aggiunge una nuova forma. Se le prestazioni non è un problema, si potrebbe fare qualcosa di simile, così:

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

Si prega di notare: ho scritto questo qui in fretta, ed è pensata per illustrare un concetto - molti miglioramenti possono essere fatti. Ad esempio, è possibile utilizzare una mappa con le due classi Shape come chiave per migliorare le prestazioni oppure è possibile assegnare CollisionAlgorithm a parametri generici per eliminare la necessità di eseguire il cast delle forme. Tuttavia, tieni presente che questo approccio richiede una ricerca nel contenitore dell'algoritmo ogni volta che è necessario eseguire un test di collisione.

+0

Aggiunta l'ultima opzione. –