【问题标题】:Iterating through a list of a super class while allowing removal and cast as subtype遍历超类列表,同时允许删除和转换为子类型
【发布时间】:2013-12-21 20:45:54
【问题描述】:

我正在为较旧的街机游戏编写引擎。除了引擎,我还在编写 Space Invaders。这个想法是让构成引擎的类足够通用,以适应各种街机游戏,然后像 Space Invaders 这样的特定游戏扩展引擎并填充特定部分。

我有一个开发成两个抽象类的游戏引擎,它们创建一个游戏循环并根据循环连续之间的经过时间更新精灵。在一类游戏引擎中,我有一个资源管理器,其中包含敌人、敌人射弹和玩家射弹的 Sprite 列表。资源管理器当前将这些列表存储为 Sprite 类型的 ArrayList。然后,游戏引擎在更新方法中遍历这些 Sprite 列表并更新 Sprite。

然后我开始研究 Space Invaders,并意识到我需要为我的玩家飞船(生命、玩家状态)扩展 Sprite,还需要为外星人(点数、外星人状态)扩展 Sprite。我仍然可以将我的播放器作为 Sprite 存储在资源管理器中,当我需要在 SpaceInvaders 类中使用播放器时,我可以调用 ResourceManager.getPlayer() 将播放器作为 Sprite 返回,但随后我可以将其转换为播放器。

当我尝试与外星人合作时,问题就出现了。我制作了一个也扩展了 Sprite 的 Alien 类。当我创建外星人时,我将它们创建为 Alien 对象,然后将它们传递给资源管理器,资源管理器将它们存储在 Sprite 类型的 ArrayList 中。在我的碰撞检查方法中,我这样遍历外星人列表:

for (Iterator<Sprite> iter = resources.getPlayerProjectiles().iterator();
            iter.hasNext();) {
        boolean shotRemove = false;
        Sprite sprite = iter.next();
        for (Iterator<Sprite> iterAlien = resources.getEnemies().iterator();
                iterAlien.hasNext();) {
            Sprite alien = iterAlien.next();
            if (collision(sprite,alien)) {
                shotRemove = true;
                iterAlien.remove();
            }
        }
        if (sprite.getY() < 100 || shotRemove)
            iter.remove();
    }

此时我想使用 Alien 独有的方法,例如在 shotRemove = true 行下方写入 score += alien.getPoints()。但是该方法只知道alien 是Sprite,因为iterAlien 是Sprite 类型的迭代器,因为resources.getEnemes() 是Sprite 类型的列表。如果我尝试将外星人投射为外星人,我会得到一个 classCastException。

总而言之,我希望能够使资源管理器中的列表尽可能通用(Sprite),因为引擎只知道 Sprite,但是当我遍历它们时能够使用列表游戏特定类作为扩展 Sprite 的类(在本例中为 Alien)。

我曾尝试在资源管理器中使用像 E extends Sprite 这样的泛型,但我无法让它工作。我已经阅读了一些关于通配符(?)的内容,但我认为这不是我想要做的。我认为 E extends Sprite 是我想要的,因为该列表是一些扩展 Sprite 的通用类型,可以被视为 Sprite(在引擎中)或 E(SpaceInvaders 中的外星人)。

【问题讨论】:

  • 其实我认为至少一个演员应该工作。如果并非总是如此,您的 getEnemies 会返回一个不仅包含 Alien 对象的列表。此外,如果您确实在列表中混合了子类型,那么如果您想调用特定于子类型的方法,则无法进行强制转换。泛型对此无济于事。

标签: list generics inheritance game-engine


【解决方案1】:

您不能保证 Sprite 是外星人,所以请使用 instanceof,例如:

if (sprite instanceof Alien) {
    Alien alien = (Alien)sprite;
    // do something with alien
}

泛型在这里帮不了你。

【讨论】:

  • 我知道我没有准确描述情况,但是,至少在这种情况下,我可以保证 Sprite 是外星人。我为敌人(在 SpaceInvaders 中都是 Alien 类型)、玩家射弹和敌人射弹保留了单独的列表。
  • 为什么你没有一个单独的 getter 用于返回 Alien 类型列表的敌人?
  • 所以我知道添加到 resources.getEnemies() 的每个 Sprite 都是 Alien 类型,但被存储为 Sprite。我有点困惑,因为只是尝试强制转换 (Alien)alien 会导致类强制转换异常。您创建新 Alien 引用并将其分配给 (Alien)alien 的方法不再创建异常,但也不能正确允许外星人引用执行任何 Alien 方法。实际上,我的代码永远不会进入 if 块,因为它不会将外星人识别为 instanceof Alien。
  • 也许这不是正确的做法,但我想让引擎保持通用性并适应不同的特定游戏。引擎有一个 Sprite 类,这就是我希望引擎知道的细节。我想将资源管理器保留为引擎的一部分,而不是特定游戏实现的一部分。
  • 非常抱歉到目前为止所有阅读并帮助过我的愚蠢行为的人。问题是我存储了其中一个精灵,然后克隆它以供重用。所以问题永远不会将它们存储为 Sprite,问题是/是 Sprite 类型是从克隆返回的内容。所以 ArrayList 存储的是 Sprites 而不是 Aliens。我现在不确定我是否能够像我希望的那样让资源管理器保持通用和低级。再次感谢所有阅读并提供帮助的人。
猜你喜欢
  • 1970-01-01
  • 2010-11-30
  • 2012-08-20
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
相关资源
最近更新 更多