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