2013-08-07 97 views
5

我在java中製作了一個簡單的基於物理的遊戲,我被困在實施碰撞檢測方法中。我有幾個繼承自comman基類的形狀的類。我將所有可見對象存儲在形狀類的數組列表中。我已經爲每個可能的物體碰撞創建了幾種碰撞檢測方法。 當我開始實施我結束了這樣的代碼的方法:在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

我仍在處理你的主要問題,但是首先,你可能要考慮使用'if(s1 instanceof Ball)'而不是'getClass()'。這是一個更加標準和打字高效的方式。 – snickers10m

+0

這些是你自己的課程嗎? ('形狀','球','塊') 如果沒有,你可以在你正在使用的任何API中找到預製的碰撞檢測。 – snickers10m

+0

不知道性能有多重要,但您可以註冊碰撞算法列表(或使用由Shape類別鍵入的映射),然後在給定形狀類別的列表中找到適當的算法。查看下面添加到我的答案的新示例。 –

回答

3

如果你不介意碰撞檢測代碼中的對象本身,你可以通過做一些像消除檢查的一側如果有必要,Shape中的形狀的某些組合 - 你甚至可以擺脫碰撞,只是使例如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提供通用參數以消除對Shapes的需要。不過,請記住,每次需要執行碰撞測試時,此方法都需要在算法容器中進行查找。

+0

添加最後一個選項。 –