我目前正在使用组件模式开发游戏,并且总是想知道如何完成。 我有一个实体,实际上只是一袋组件。每个组件都扩展了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);
}
}
}
一些示例组件:
public class GraphicsComponent扩展了Component {
公共位图位图; public Rect currentFrameRect; private ArrayList spriteAnimations; public SpriteAnimation currentAnimation; public int x = 0; public int y = 50;上市 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]; }
@Override public void draw(Canvas canvas){
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()等任何特定函数,因为我只是返回了一个基本的Component。
我想根据传入 getComponent()的类返回 GraphicsComponent 或 InteractiveComponent 。
答案 0 :(得分: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()
检查,具体取决于您想要的确切行为。
答案 1 :(得分:2)
其他人建议将低价转型作为解决方案。我会说:重新设计。
如果您发现自己需要向下倾斜,那么它表明您可能存在架构问题。事实上,你有。您希望访问每个对象,但不能以多态方式访问。因此,尝试通过超类型的容器访问特定对象是不自然的/无益的/低效的。
我建议:
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) {
...
}
}
}
答案 2 :(得分:0)
以这种方式收到组件后,您必须将其强制转换为类类型。然后你可以访问getHeight()等。该对象根本不知道是一个graphicComponent,但它是。
答案 3 :(得分:0)
好吧,该函数返回Component
。如果您知道您已请求特定组件,请转换结果:
GraphicsComponent gc = (GraphicsComponent)(gameEntityInstance.getComponent(GraphicsComponent.class));
答案 4 :(得分:0)
当你致电getComponent()
并从该方法中删除Class
参数时,最好的选择是投票。
因此,getComponent
会返回Component
,可以投放到InteractiveComponent
或GraphicsComponent
中:
public Component getComponent() { /* its contents */ };
GraphicsComponent gc = (GraphicsComponent)...getComponent();
InteractiveComponent ic = (InteractiveComponent)...getComponent();