Java 在oop中实现碰撞检测器的最佳方法
我正在用java制作一个简单的基于物理的游戏,我一直在实现碰撞检测方法。我有几个从comman基类形状继承的类。我将所有可见对象存储在shape类的arraylist中。我为每个可能的对象碰撞创建了几种碰撞检测方法。 当我开始实现这些方法时,我最终得到了如下代码:Java 在oop中实现碰撞检测器的最佳方法,java,oop,collision-detection,Java,Oop,Collision Detection,我正在用java制作一个简单的基于物理的游戏,我一直在实现碰撞检测方法。我有几个从comman基类形状继承的类。我将所有可见对象存储在shape类的arraylist中。我为每个可能的对象碰撞创建了几种碰撞检测方法。 当我开始实现这些方法时,我最终得到了如下代码: private void collision_detector(Shape s1,Shape s2){ if(s1.getClass()==Ball.class) if(s2.getClass() == Bl
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) { ... }
}
这也使您可以在必要时自由地为形状本身中的某些形状组合实施碰撞算法--您甚至可以消除碰撞,只需创建例如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.collizeswithball是不必要的,因为可以使用Ball.collizeswithblock
每次添加新形状时,仍然必须更新上述代码。如果性能不是问题,您也可以这样做:
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);
公共抽象类冲突算法{
公共抽象布尔ChanCuldE(Cyrm)仍然在处理你的主要问题,但首先,你可能想考虑使用<代码>(S1实例)< /C> >而不是<代码> GeCaseType()/代码>。这是一个更标准和打字的有效方式。这是你自己的类吗?(Shape
,Ball
,Block
)如果没有,您可能会在正在使用的任何API中找到预先制作的碰撞检测。不确定性能有多重要,但您可以注册碰撞算法列表(或使用由Shape类设置关键帧的映射)然后在给定形状类的列表中找到合适的算法。请参阅下面我的答案中添加的新示例。我在采访软件工程师时基本上问了这个设计问题10多年了。这真的将男人和男孩区分开来。额外的挑战:如何实现这一点,以便在编译时发现忘记了一些代码或忘记在编译时实现其中一个算法?