2010-02-10 19 views
1

J'ai un jeu composé de navires qui volent sur une grille 2d. J'écris une fonction qui prend un emplacement, et détermine si la cible (prédéfinie) peut être touchée à partir de là. Cela nécessite simplement de vérifier tous les carrés de la grille dans la ligne de tir de l'agresseur potentiel.C# XNA: Comment supprimer la répétition de cette fonction simple?

Dans la plupart des cas, ceci est une croix, formé comme ceci:

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

SHOT_RANGE est la distance maximale d'un coup de feu peut se déplacer, et le navire de tir est actuellement situé à (currX, currY).

Le code pour vérifier ces deux lignes est assez simple:

 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; 
      } 
     } 

Cependant, sur certains « tuiles électriques » le navire peut aussi tirer en diagonale. Tous ces carrés doivent être vérifiés aussi. C'est là que la répétition entre en jeu. Pouvez-vous voir un moyen de le faire avec moins de code?

/// <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; 
    } 

MISE À JOUR utiliser la suggestion de Carra, et je compris que je pouvais éliminer deux des boucles de contrôle en augmentant les diagonales des limites supérieures.

Répondre

1

Je pense que cela peut être fait plus facile sans boucle, au moins pour le balayage horizontal et vertical:

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; 

En ce qui concerne les diagonales, ils sont un triangle avec un angle de 90 degrés: (a² + b² < c²)

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; 

J'espère que ce sera quelque chose comme ça que vous cherchez?

+0

mais pour les diagonales, cela ne serait-il pas vrai si le tireur est à '(3, 3)' et que la cible est '((1, 2)'? Ce ne serait pas correct. le navire ne tire que le long des diagonales. (Donc à partir de '(3, 3)', un vaisseau pourrait frapper '(2, 2)', '(1, 1)', etc.) –

+0

Bon point. Mais c'est un angle de 90 degrés donc a == b. – Carra

0

Je pense qu'une meilleure conception serait de changer votre fonction d'avoir une signature similaire à:
public bool CanShoot(IShootable potentialTarget)

Cette méthode pourrait être membre d'une classe de navire. Chaque objet Ship connaîtrait ses propres capacités de tir. Tout ce que vous vouliez pouvoir tirer pourrait implémenter IShootable.

En ce qui concerne votre question, il semble y avoir un moyen beaucoup plus facile. Semblable à ce que Carra a dit, vous pouvez juste vérifier si la valeur absolue de la différence de chaque coordonnée est inférieure à votre gamme de tir. Sinon, renvoyez false. Sinon, s'ils sont sur une mosaïque de puissance, renvoyez true. Si elles ne sont pas sur une mosaïque de puissance, vérifiez que la coordonnée x ou la coordonnée y correspond, sinon renvoyez false, sinon renvoyez true. Ceci est basé sur l'hypothèse qu'un navire ayant une portée de tir 2 à (0,0) peut tirer sur un navire en (2,2). Je suppose que parce que le code que vous avez posté le permettrait.