如果您不介意将碰撞检测代码放在对象本身中,则可以通过执行以下操作来消除检查的一面:
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) { ... }
}
如果有必要,这也可以让你自由地为Shape中的Shapes的某些组合实现碰撞算法 – 你甚至可以摆脱碰撞Block.collideWithBall,Block.collideWithBlock和Ball.collideWithBlock,适当地调用它们,例如:
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) {
...
}
}
就个人而言,我更喜欢后者,因为它保留了相关类中包含的碰撞代码.请注意,Block.collidesWithBall是不必要的,因为可以使用Ball.collidesWithBlock.
每次添加新形状时,您仍然需要更新上面的代码.如果性能不是问题,你也可以这样做:
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 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);
请注意:我在这里快速输入,这是为了说明一个概念 – 可以进行许多改进.例如,地图可以与两个Shape类一起使用作为提高性能的关键,或者可以为CollisionAlgorithm提供通用参数以消除转换形状的需要.但请记住,每次需要执行碰撞测试时,此方法都需要在算法容器中查找.