2011-12-13 116 views
2

我目前正在使用零部件模式進行遊戲,並一直在想如何做到這一點。 我有一個實體,實際上只是一個組件包。每個組件都擴展了Component類,它只具有一些基本功能。返回需要超類的擴展類

擴展組件類,創建新的組件,用於處理輸入,圖形等。現在出現這個問題;當我試圖從實體中獲取特定的組件時,它總是返回基本的Component類,這阻止了我使用特定的組件功能。

public class GameEntity 
{ 
    private ArrayList<Component> components; 

    public GameEntity() 
    { 
     components = new ArrayList<Component>(); 
    } 

    public void addComponent(Component component) 
    { 
     components.add(component); 
    } 

    public void update() 
    { 

    } 

    public Component getComponent(Class type) 
    { 
     for (Component component : components) 
     { 
      if(component.getClass() == type) 
      { 
       //return component as Class; 

      } 
     } 
     return null; 
    } 


    public void draw(Canvas canvas) 
    { 
     for (Component component : components) 
     { 
      component.update(); 
      component.draw(canvas); 
     } 
    } 

} 

一些示例組件:

公共類GraphicsComponent延伸元器件{

公共位圖的位圖; public Rect currentFrameRect; private ArrayList spriteAnimations; public SpriteAnimation currentAnimation; public int x = 0; public int y = 50; public GraphicsComponent(){ spriteAnimations = new ArrayList(); }

/** 
* Adds image [converts to spriteanimation] 
* @param image 
*/ 
public void addImage(Bitmap image, String label) 
{ 
    Rect[] tmpRects = {new Rect(0, 0, image.getWidth(), image.getHeight())} ; 
    addAnimation(new SpriteAnimation(
      image, tmpRects, label 
    )); 
} 

public void addAnimation(SpriteAnimation spriteAnimation) 
{ 
    spriteAnimations.add(spriteAnimation); 

    if(currentAnimation == null) 
    { 
     currentAnimation = spriteAnimation; 
    } 
} 


@Override 
public void update() 
{ 
    currentFrameRect = currentAnimation.frames[currentAnimation.currentFrame]; 
} 

@覆蓋公共無效畫(油畫畫布){

if(currentAnimation != null) 
    { 
     currentAnimation.draw(x, y, canvas); 
    }  } 
public int getWidth() 
{ 
    return currentAnimation.frames[currentAnimation.currentFrame].width(); 
} 

public int getHeight() 
{ 
    return currentAnimation.frames[currentAnimation.currentFrame].height(); 
} 
} 


public class InteractiveComponent extends Component 
{ 
    public GraphicsComponent graphics; 

    public InteractiveComponent(GraphicsComponent graphics) 
    { 
     this.graphics = graphics; 
    } 

    public boolean isOver(int tapX, int tapY) 
    { 
     //left top right bottom 
     if(tapX > graphics.x && tapX < graphics.x + graphics.getWidth() && 
      tapY > graphics.y && tapY < graphics.y + graphics.getHeight() 
     ) 
     { 
      return true; 
     } 
     return false; 
    } 

} 

似乎有一些問題與代碼的格式,但它應該是清楚的。 我無法訪問graphicComponent中的getHeight()或interactiveComponent中的isOver(),因爲我只是返回一個基本的組件。

我想基於我進入getComponent()類返回一個GraphicsComponentInteractiveComponent

+0

降級到你想要的課程。 –

+0

這是太多的示例代碼。 – millimoose

+0

我對「downcasting」這個詞不熟悉,感謝提及它。 我爲冗長的代碼表示歉意,我擔心我的問題還不夠清楚。 – omgnoseat

回答

3

什麼你正在試圖做的似乎架構犯罪嫌疑人給我,但仍然可以使用泛型一個「乾淨」的方式來完成,而你已經在傳遞類對象作爲一種象徵:

class Animals { 
    List<Animal> animals = new ArrayList<Animal>(); 

    public <T extends Animal> T getAnimal(Class<T> type) { 
     for (Animal animal : animals) { 
      if (type.isAssignableFrom(animal.getClass())) { 
       return type.cast(animal); 
      } 
     } 
     return null; 
    } 
} 

class Main { 
    public static void main(String[] args) { 
     Animals animals = new Animals(); 
     animals.getAnimal(Cat.class).meow(); 
     animals.getAnimal(Dog.class).bark(); 
    } 
} 

interface Animal {} 

class Cat implements Animal { 
    public void meow() {} 
} 

class Dog implements Animal { 
    public void bark() {} 
} 

您可以==equals()代替isAssignableFrom()檢查取決於你想要的確切行爲。

+0

''''參數和一個'T'返回值是告訴編譯器一種方法的返回類型取決於參數值的方式 - 這就是你如何說「返回這種類型的東西」。 – millimoose

+0

在結構上,它*看起來像*你有一堆單身 - 通常只有一個類型實例存在的對象。處理這種流行的方式是使用IoC容器和依賴注入來避免編寫一個擁有許多管理這些類的臃腫類的代碼。 IoC容器的存在意義在於以通用的方式實現這個模式。嘗試查看[Guice](http://code.google.com/p/google-guice/)或[Spring Framework](http://www.springsource.org/)。 – millimoose

+0

我可能理解不正確,但可能有多個實體都有其自己的組件。所以可以有多於一個所述組件的實例。我會嘗試看看框架,但它似乎有點高於我的水平說實話:( 我有另一個問題,我剛剛遇到:我擴展了graphicsComponent,所以我可以設置一些簡單的模板來使用,在哪裏所有的動畫已經預先定義好了。但是,因爲它只檢查它是否與graphicsComponent匹配,而不是它的任何超級類,它將返回null :( 任何方式來檢查超級類別? – omgnoseat

0

一旦以這種方式接收到組件,就必須將其重新轉換爲類類型。然後你可以訪問getHeight()等等。該對象根本不知道是一個graphicComponent,但它是。

0

那麼,函數返回一個Component。如果你知道你所請求的特定組件,把結果:

GraphicsComponent gc = (GraphicsComponent)(gameEntityInstance.getComponent(GraphicsComponent.class)); 
0

你最好的選擇是,當你調用getComponent()投和刪除從方法Class說法。

所以,getComponent將返回可鑄造成要麼InteractiveComponentGraphicsComponent一個Component

public Component getComponent() { /* its contents */ }; 

GraphicsComponent gc = (GraphicsComponent)...getComponent(); 
InteractiveComponent ic = (InteractiveComponent)...getComponent(); 
+0

我有點不喜歡演員,不知道爲什麼,但使用它們感覺很難受。看起來像一個很好的解決方案,謝謝。 – omgnoseat

+0

我感覺一樣,但我還沒有找到更好的方法來做到這一點。 – Jon

2

也有人建議向下轉換作爲一種解決方案。我會說:重新設計

如果你發現自己需要downcast,那麼它表明你可能有一個架構問題。事實上,你有。你想訪問每個對象,但不是以多態的方式。所以試圖通過超類型的容器訪問特定的對象是不自然的/無益的/效率低下的。

我建議:

class GameEntity { 
    private GraphicsComponent graphics; 
    private InteractiveComponent interactive; 
    private SoundComponent sound; 

    private List<Component> components; 

    public GameEntity() { 
     components.add(graphics); 
     // etc. 
    } 

    public GraphicsComponent getGraphics() { return graphics; } 
    // etc. 

    public void draw() { 
     for (Component c : components) { 
      ... 
     } 
    } 
} 
+0

雖然這種情況下的重新設計可能是合適的,但如果您需要沮喪,那麼您遇到體系結構問題並非總是如此。 –

+0

@increment:的確,這就是我說「表示」的原因。情況並非總是如此,但通常情況是這樣。 –

+0

您的編輯增加了*可能*這似乎更合適,但我甚至會削弱* may *,但這可能只是意見。在您的重建建議中,您可能仍然需要解決這些組件看起來是動態的,需要重複繪製/更新。 –