java – 在oop中实现碰撞检测器的最佳方法
我在
java中制作了一个简单的基于物理的游戏,我坚持实现碰撞检测方法.我有几个继承自comman基类形状的类.我将所有可见对象存储在shape类的arraylist中.我已经为每个可能的对象碰撞创建了几种碰撞检测方法.
当我开始实现这些方法时,我最终得到了这样的代码: 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); } 它只是感觉不是实现碰撞检测的正确方法,因为我必须更新此方法以检查每次添加新形状(如三角形或六边形)时的每种可能组合. 解决方法
如果您不介意将碰撞检测代码放在对象本身中,则可以通过执行以下操作来消除检查的一面:
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<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); 请注意:我在这里快速输入,这是为了说明一个概念 – 可以进行许多改进.例如,地图可以与两个Shape类一起使用作为提高性能的关键,或者可以为CollisionAlgorithm提供通用参数以消除转换形状的需要.但请记住,每次需要执行碰撞测试时,此方法都需要在算法容器中查找. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |