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.
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
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
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. –