【问题标题】:How to Simplify Multiple IF Statements?如何简化多个 IF 语句?
【发布时间】:2020-03-15 03:09:27
【问题描述】:

我正在用 Java 编写一个简单的小行星游戏。并找到这个问题(不是真正的问题,我的解决方案效果很好,但看起来很难看)。我只想知道有没有办法简化我的代码。

我的游戏中有一些对象。船、流星、子弹和硬币。它们都是 GameObject 的子类。为了处理碰撞,在 MyGame 类中我有这些函数。

private void ship_hit_meteor(Ship ship, Meteor meteor){}
private void bullet_hit_meteor(Bullet bullet, Meteor meteor){}
private void ship_hit_coin(Ship ship, Coin coin){}
//...and so on

为了进行碰撞检查,我将所有对象放在 1 个大 objArray 中。 然后我迭代数组以检查冲突。我就是这样做的:但是想象一下,如果我有 100 种类型的对象。

//inside the collision loop
GameObject a = objArray[i];
GameObject b = objArray[j];
if(a instanceof Ship && b instanceof Meteor ){
    ship_hit_meteor((Ship)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Ship){
    ship_hit_meteor((Ship)b, (Meteor)a);
}
else if(a instanceof Bullet && b instanceof Meteor){
    bullet_hit_meteor((Bullet)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Bullet){
    bullet_hit_meteor((Bullet)b, (Meteor)a);
}
//... end of the loop

有什么办法可以简化吗?

谢谢。

【问题讨论】:

  • 我想这应该是正确的地方codereview.stackexchange.com
  • Bullet 击中MeteorMeteor 击中Bullet 的区别在哪里?
  • 您可以在 GameObject 中拥有一个名为 collision() 的抽象方法,每个子类都实现该方法。让它获取另一个 GameObject,然后在实现中处理每个对象。 IE。在Ship.collision(GameObject a) 中,您可以有一个用于 a 的 switch 语句
  • 不管谁打谁,我都不会在你的 GameObject 类中创建 100 个方法,而是在你的每个类中实现一些简单的 hit(GameObject object) 方法。然后你可以超载它们。在你的Ship 类中说你可以实现hit(Meteor meteor){...} 或者hit(Bullet bullet)。然后你决定是否摧毁这艘船或减少它的生命值或其他什么。您可以通过调用a.hit(b) 来简单地触发它,而无需在运行时实际“知道”ab 是什么类。
  • 如果您的代码有效,那么这里就离题了,应该像 Tony 前面提到的那样在代码审查时询问。

标签: java android libgdx game-development


【解决方案1】:

如果您有 100 种类型的对象,您会发现自己编写了 5050 个方法,如果您为每种对象类型组合编写一个单独的方法。 (如果有 n 个类型,公式为 n(n-1)+n 方法)。这甚至没有考虑到如何分派给正确的人,这就是您在这里遇到的问题。

更好的方法是拥有一个通用的碰撞处理方法,该方法知道如何根据碰撞对象的属性处理所有碰撞。然后可以将此类属性表示为方法,以及允许碰撞逻辑操纵碰撞对象的辅助方法。例如

public interface Collides {
    // properties
    int damageDealtOnImpact();
    boolean isReward();
    boolean isIndestructible();
    boolean isDestroyedOnImpact();

    // impact methods
    void damage(int damage);
    void destroy();
    void split();
    void changeCourse(Vector impactVector);

    // ... and so on, whatever you need
}

这样,添加对象类型应该相对轻松。尽管有时新类型的对象可能需要新的属性。在这种情况下,您的通用碰撞处理方法将受到影响,您可能需要在现有对象上实现额外的属性。但它胜过添加 101 个新方法并将其分派给它们。

【讨论】:

    【解决方案2】:

    也许你可以创建一个接口,比如说“SpaceObject”,你所有的交互类都会实现它。接口有一个方法 handleCollision() 并且类应该重写它。在那里,您将碰撞逻辑、损坏等放入 HandlerService(您的 sn-p 所在的地方)中,您只需接收一个 SpaceObjects 列表并调用它们的 handleCollision 方法。

    【讨论】:

      【解决方案3】:

      虽然我对 Java 一无所知,但我认为您的代码需要对子例程组织进行一些思考。我宁愿为每个对象定义 1 自己的“击中”程序。在主流程中,根据有效的对象名称列表检查第一个对象,然后使用参数 2 调用适当的“object.hitting”。检查参数的有效性输出单个数字或 0,您可以在此处“再次切换”。

      【讨论】:

        【解决方案4】:

        您首先使用一些四叉树库而不参考对象类型来检查冲突。

        看到这个答案 Quadtree for 2D collision detectionEfficient (and well explained) implementation of a Quadtree for 2D collision detection

        然后-.. 你可以自己过滤碰撞。

        https://www.iforce2d.net/b2dtut/collision-filtering

        所以设置objectIDs

        public static final short xUSER_SHIP      = 0x0001;
        public static final short xUSER_BULLET    = 0x0002;
        

        以及由任何碰撞的逻辑或创建的碰撞类别掩码

        public static final short USER_SHIP_MASK = xPICKUP | xWALL | xENEMY_SHIP;
        

        (请记住,您必须声明 A 击中 B 并且 B 击中 A。

        然后你在通过碰撞列表时实施

        bool collide =
                  (filterA.maskBits & filterB.categoryBits) != 0 &&
                  (filterA.categoryBits & filterB.maskBits) != 0;
        

        但是,完成所有这些工作需要做很多工作。您可能更喜欢每个正方形的粗粒度网格比任何单个物体(硬币、小行星等)都大。每个对象都会更新其在此主网格上的 x,y 位置。对于每个对象,在路线网格上查找其封闭的正方形(它可能与其直接所有者重叠,但不能越过周围的单元格),以检查“基于网格的碰撞检测”或“基于瓷砖的碰撞检测”的碰撞检查。这将是最简单的,您可以根据自己的喜好自行实现如果您将所有内容都视为碰撞圆圈,那就更容易了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-10-06
          • 1970-01-01
          • 2021-11-20
          • 2014-06-18
          • 1970-01-01
          • 2021-12-07
          • 1970-01-01
          相关资源
          最近更新 更多