我有一个游戏,包括在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的建议,我意识到我可以通过增加上限消除两个检查对角线的循环。
答案 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)处的船上射击。我假设这是因为您发布的代码允许这样做。