如何从这个简单的功能中删除重复?

时间:2010-02-10 19:26:37

标签: c# xna dry

我有一个游戏,包括在2d网格上飞来飞去的船只。我正在编写一个获取位置的函数,并确定是否可以从那里击中(预定义的)目标。这只需要检查潜在攻击者的火线中的所有网格方块。

在大多数情况下,这是一个十字架,形成如下:

(currX +/- SHOT_RANGE, currY) and (currX, currY +/- SHOT_RANGE)

SHOT_RANGE是射击可以移动的最大距离,射击船目前位于(currX, currY)

检查这两行的代码非常简单:

        for (int i = x - SHOT_RANGE; i < x + SHOT_RANGE; i++) {
            if (target.TileX == i && target.TileY == y) {
                return true;
            }
        }

        for (int j = y - SHOT_RANGE; j < y + SHOT_RANGE; j++) {
            if (target.TileX == x && target.TileY == j) {
                return true;
            }
        }

然而,在某些“动力瓷砖”上,船也可以对角地射击。还必须检查所有这些方块。这就是重复的地方。你能用更少的代码看到一种方法吗?

    /// <param name="x">Current x-coord of the potential ship</param>
    /// <param name="y">Current y-coord of the potential ship</param>
            private bool CanShootTargetFrom(int x, int y) {

        if ((target.TileX == x && Math.Abs(target.TileY - y) <= SHOT_RANGE) || (target.TileY == y && Math.Abs(target.TileX - x) <= SHOT_RANGE)) {
            return true;
        }

        if (board.IsPowerTileAt(x, y)) {
            int i = x - SHOT_RANGE;
            int j = y - SHOT_RANGE;
            while (i != x + SHOT_RANGE && j != y + SHOT_RANGE) {
                if (target.TileX == i && target.TileY == j) {
                    return true;
                }
                i++;
                j++;
            }
            i = x - SHOT_RANGE;
            j = y + SHOT_RANGE;
            while (i != x + SHOT_RANGE && j != y - SHOT_RANGE) {
                if (target.TileX == i && target.TileY == j) {
                    return true;
                }
                i++;
                j--;
            }
        }

        return false;
    }

更新以使用Carra的建议,我意识到我可以通过增加上限消除两个检查对角线的循环。

2 个答案:

答案 0 :(得分:1)

我认为没有循环就可以更容易,至少对于水平和垂直扫描:

class Ship{int x;int y}

Ship s;//your ship
Ship t;//target

if(
  (s.y == t.y && abs(s.x-t.x) <= SHOT_RANGE) 
  ||
  (s.x == t.x && abs(s.y-t.y) <= SHOT_RANGE)
  )
   return true;

对于对角线,它们是一个90度角的三角形: (a²+b²

int a = abs(s.x - t.x)
int b = abs(s.y - t.y)
if(a == b && a * a + b * b <= shot_range * shot_range)
  return true;

我希望你正在寻找这样的东西吗?

答案 1 :(得分:0)

我认为更好的设计是将您的功能更改为具有类似于以下的签名:
public bool CanShoot(IShootable potentialTarget)

此方法可以是Ship类的成员。每个Ship对象都知道自己的触发功能。你希望能够被射击的任何东西都可以实现IShootable。

关于你的问题,似乎有一种更简单的方法。与Carra所说的类似,您可以检查每个坐标的差值的绝对值是否小于您的射程。如果没有,则返回false。否则,如果它们在电源磁贴上,则返回true。如果它们不在电源磁贴上,请检查以确保x坐标或y坐标匹配,否则返回false,否则返回true。

假设在(0,0)处具有射程2的船可以在(2,2)处的船上射击。我假设这是因为您发布的代码允许这样做。