2013-08-07 16 views
5

私は単純な物理ベースのゲームをJavaで作成していますが、衝突検出メソッドの実装にはまっています。私は、いくつかのクラスを持っています。私はすべての可視オブジェクトを形状クラスのarraylistに格納しています。私はオブジェクトの可能なすべての衝突のためのいくつかの衝突検出メソッドを作成しました。私はこのようなコードになってしまったのメソッドの実装を始めたとき :oopで衝突検出器を実装する最善の方法

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) { ... } 
} 

:あなたがオブジェクトで自分自身を衝突検出コードを入れてもかまわない場合

+2

私はあなたの主要な質問に取り組んでいますが、1つは、getClass()の代わりに 'if(s1 instanceof Ball)'を使うことです。これはもう少し標準的でタイピング効率のよい方法です。 – snickers10m

+0

これらはあなたのクラスですか? ( 'Shape'、' Ball'、 'Block') もしそうでなければ、あなたが使用しているAPIであれば、あらかじめ作成された衝突検出を見つけることができます。 – snickers10m

+0

パフォーマンスの重要性は不明ですが、衝突アルゴリズムのリストを登録したり、シェイプクラスが与えられたマップを使用したりして、シェイプクラスが与えられたリストで適切なアルゴリズムを見つけることができます。下の私の答えに追加された新しい例を見てください。 –

答えて

3

、あなたは次のように何かをすることにより、チェックの片側を排除することができます必要に応じてシェイプのシェイプの特定の組み合わせ - あなたはCollisionを取り除くこともできます。 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) { 
     ... 
    } 
} 

、I種類の後者のような、より良い、それは、関連するクラスに含まれる衝突コードを保持するので。 Ball.collidesWithBlockを使用できるので、Block.collidesWithBallは不要です。

新しい図形を追加するたびに上記のコードを更新する必要があります。パフォーマンスが問題ではない場合、あなたにも、このような何かを行うことができます:

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); 

に注意してください。を私はすぐにここにこれを入力し、概念を説明するためのものだ - 多くの改良を行うことができます。たとえば、パフォーマンスを向上させるキーとして2つのシェイプクラスをマップとして使用することも、CollisionAlgorithmにジェネリックパラメータを渡してShapeをキャスティングする必要をなくすこともできます。ただし、この方法では、衝突テストを実行する必要があるたびに、アルゴリズムコンテナでルックアップが必要です。

+0

最後のオプションが追加されました。 –