Traçage d'étendue à l'échelle de la mosaïque sur une grille

8

Je travaille actuellement sur A * pathfinding sur une grille et je cherche à lisser le chemin généré, tout en considérant l'étendue du personnage qui se déplace le long de celui-ci. J'utilise une grille pour la recherche de chemin, mais le mouvement des personnages est en itinérance libre, pas un mouvement strict de tuile à tuile.

Pour obtenir un chemin plus fluide et plus efficace, je fais des traces de ligne sur une grille pour déterminer s'il y a des tuiles impossibles à parcourir entre les tuiles pour raser les coins inutiles.

Cependant, comme une trace de ligne a une étendue nulle, elle ne prend pas en compte l'étendue du caractère et donne de mauvais résultats (ne renvoyant pas de tuiles irrécupérables simplement manquées par la ligne, provoquant des collisions indésirables).

Donc, ce que je recherche, c'est plutôt qu'un algorithme de ligne qui détermine les tuiles en dessous, j'en cherche un qui détermine les tuiles sous une ligne d'étendue à l'échelle de la tuile. Voici une image pour aider à visualiser mon problème!

Voici une image pour aider à visualiser mon problème

Quelqu'un a-t-il une idée? J'ai travaillé avec la gamme Bresenham et d'autres alternatives, mais je n'ai pas encore compris comment résoudre ce problème spécifique.

Larolaro
la source
J'utiliserais deux lignes de Besenham à une largeur de demi-tuile.
Jonathan Connell

Réponses:

1

Que diriez-vous si vous tracez une ligne à partir de chaque coin de la «tuile», vous êtes sur chaque coin de la tuile où vous voulez aller. Vous pouvez probablement même optimiser cela à 3 lignes au lieu de quatre. Cela ne détecterait-il pas correctement toutes les tuiles du chemin?

En ce qui concerne les chemins plus lisses, consultez les articles sur le «comportement de pilotage», en particulier ceux qui le combinent avec A *, par exemple ces liens:

Roy T.
la source
0

Je viens d'implémenter cet algorithme pour un de mes jeux il y a quelques jours! (-8

Voici mon idée sous forme d'image:

entrez la description de l'image ici

Notez que l'algorithme fonctionne avec des rectangles de n'importe quelle taille. il est basé sur le fait qu'un coin du rectangle entre toujours en premier avec n'importe quelle ligne de grille. Cela signifie que vous ne pouvez tracer qu'un seul rayon et obtenir toutes les intersections dont vous avez besoin.

Voici l'algorithme étape par étape:

  1. Choisissez le coin "avant" de votre rectangle. Par exemple, dans l'image, la direction de traçage se situe dans le quadrant supérieur droit, nous choisissons donc le coin supérieur droit.
  2. Tracez le rayon (de largeur nulle) de ce coin jusqu'à votre destination. Vous devez parcourir toutes les intersections de votre rayon avec des lignes de grille.
  3. Pour toutes les intersections du rayon avec des lignes de grille, placez votre rectangle au point d'intersection. Son côté se situerait exactement le long d'une ligne de grille, touchant un certain nombre de cellules de grille. Ce sont les carreaux avec lesquels votre rectangle entre en collision à ce stade!

Il y a des cas de bord ici, comme quand le rayon est exactement vertical / horizontal, ou quand il frappe exactement un coin, mais ce n'est pas difficile.

Ça ne fait rien
la source
0

Cette procédure est une adaptation de bresenham, qui résout la question d'origine.

tracer une ligne de la taille d'une tuile sur une grille

final int cols = 64;
final int rows = 64;
color tiles = new color[cols*rows];

void squaretrace(int x1, int y1, int x2, int y2, color c) {
  if (x1==x2 && y1==y2) {
    tiles[x1+y1*cols] += c;
  } else {
    // make sure y1 is less or equal to y2
    if (y2 < y1) {
      int t = x1;
      x1 = x2;
      x2 = t;
      t = y1;
      y1 = y2;
      y2 = t;
    }
    // along y-axis
    if (x1==x2) {
      for(int y = y1; y <= y2; y++){
        tiles[x1 + y * cols] += c;
      }
    }
    // along x-axis
    else if (y1==y2) {
      int xLo, xHi;
      if(x1 < x2){
        xLo = x1;
        xHi = x2;
      }
      else{
        xLo = x2;
        xHi = x1;
      }
      for(int x = xLo; x <= xHi; x++){
        tiles[x + y1 * cols] += c;
      }
    }
    // northeast
    else if (x1 < x2) { 
      // NW and SE corner
      int dx = x2 - x1;
      int dy = y2 - y1;
      int m = 8;
      int k = (1<<m) * dx / dy;

      int minx = x1 << m;
      int maxx = (x1+1) << m;

      for (int y = y1; y <= y2; y++) {
        int xLo = minx >> m;
        if (y!=y1) minx += k;
        if (y<y2) maxx += k;
        int xHi = (maxx-1) >> m;
        for (int x = xLo; x <= xHi; x++) {
          tiles[x+y*cols] += c;
        }
        tiles[xLo+y*cols] += c;
        tiles[xHi+y*cols] += c;
      }
    }
    // northwest
    else {
      // NW and SE corner
      int dx = x2 - x1;
      int dy = y2 - y1;
      int m = 8;
      int k = (1<<m) * dx / dy;

      int minx = x1 << m;
      int maxx = (x1+1) << m;

      for (int y = y1; y <= y2; y++) {

        if (y<y2) minx += k;
        int xLo = minx >> m;
        int xHi = (maxx-1) >> m;
        if (y!=y1) maxx += k;

        for (int x = xLo; x <= xHi; x++) {
          tiles[x+y*cols] += c;
        }
        tiles[xLo+y*cols] += c;
        tiles[xHi+y*cols] += c;
      }
    }
  }
}
placeitintheblob
la source