Déterminer l'emplacement final du mouvement de l'IA en groupes dans un RTS 2D

8

J'ai écrit un jeu RTS (une démo pour un moteur de jeu en quelque sorte) dans lequel l'interaction de base de l'utilisateur avec le jeu consiste à sélectionner un groupe de soldats, puis à cliquer avec le bouton droit sur la carte pour les déplacer vers l'emplacement spécifié. C'est en JavaScript et vous pouvez jouer avec ici ( code ).

Ignorant le problème de la façon dont les soldats se déplacent de leur emplacement actuel vers leur destination, ma question est de déterminer quelle est leur destination réelle. Voici ce que j'ai essayé jusqu'à présent:

  • Tentative 1: dites à tous les soldats sélectionnés de se déplacer vers les coordonnées sur lesquelles la souris a cliqué. Cela a le comportement étrange que tous les soldats iront ensuite autour de la cible de manière anormale.
  • Tentative 2: Trouvez les coordonnées moyennes de tous les soldats sélectionnés, puis trouvez le décalage à partir de ce point central pour chaque soldat, et enfin traduisez ce décalage autour des coordonnées de la souris. Cela fonctionne très bien, sauf que si vos soldats sélectionnés sont très éloignés, ils ne se rapprocheront pas de la cible.
  • Tentative 3: Construisez une grille autour des coordonnées de la souris et placez chaque soldat sélectionné dans une cellule de la grille. Si chaque soldat arrive dans sa cellule assignée, cela fonctionne très bien. Cependant, les soldats sont affectés à des cellules de la grille dans l'ordre de leur apparition, donc parfois ils entrent en collision (c'est-à-dire que tous les soldats du côté droit essaieront d'aller vers le côté gauche), ce qui ne semble pas naturel.
  • Tentative 4: utilisez une grille comme précédemment, mais triez d'abord les soldats par emplacement de manière à ce qu'ils s'alignent de manière sensible, c'est-à-dire que si vous avez cliqué en dessous du groupe, les soldats en bas du groupe se retrouveront au bas de la grille lorsqu'ils atteindre leur destination. Cela fonctionne plutôt bien, mais il y a parfois des problèmes et je ne sais pas pourquoi.

Voici la fonction qui détermine les coordonnées de destination:

function moveSelectedSoldiersToMouse() {
  var w = 0, h = 0, selected = [];
  // Get information about the selected soldiers.
  myTeam.soldiers.forEach(function(soldier) {
    if (soldier.selected) {
      selected.push(soldier);
      w += soldier.width;
      h += soldier.height;
    }
  });
  var numSelected = selected.length, k = -1;
  if (!numSelected) return;
  // Build a grid of evenly spaced soldiers.
  var sqrt = Math.sqrt(numSelected),
      rows = Math.ceil(sqrt),
      cols = Math.ceil(sqrt),
      x = Mouse.Coords.worldX(),
      y = Mouse.Coords.worldY(),
      iw = Math.ceil(w / numSelected), // grid cell width
      ih = Math.ceil(h / numSelected), // grid cell height
      wg = iw*1.2, // width of gap between cells
      hg = ih*1.2; // height of gap between cells
  if ((rows-1)*cols >= numSelected) rows--;
  w = iw * cols + wg * (cols-1); // total width of group
  h = ih * rows + hg * (rows-1); // total height of group
  // Sort by location to avoid soldiers getting in each others' way.
  selected.sort(function(a, b) {
    // Round to 10's digit; specific locations can be off by a pixel or so
    var ax = a.x.round(-1), ay = a.y.round(-1), bx = b.x.round(-1), by = b.y.round(-1);
    return ay - by || ax - bx;
  });
  // Place the grid over the mouse and send soldiers there.
  for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {
      var s = selected[++k];
      if (s) {
        var mx = x + j * (iw+wg) - w * 0.5 + s.width * 0.5,
            my = y + i * (ih+hg) - h * 0.5 + s.height * 0.5;
        // Finally, move to the end destination coordinates
        s.moveTo(mx, my);
      }
    }
  }
}

Vous pouvez coller cette fonction dans la console JavaScript de votre navigateur lors de la visualisation de la démo et jouer avec elle pour changer le comportement des soldats.

Ma question est la suivante: existe-t-il une meilleure façon de déterminer l'emplacement cible de chaque soldat vers lequel se déplacer?

IceCreamYou
la source
Quelque chose appelé "flocage" peut vous être très utile et peut vous fournir le type de fonctionnalité que vous recherchez. Essayez: processing.org/examples/flocking.html ou simplement google "flocage" ou "Boids". Cela pourrait vous mettre dans la bonne direction.
Dean Knight
2
Connexes: gamedev.stackexchange.com/questions/44361 Je dirais que les "pépins" que vous rencontrez proviennent d'unités qui essaient de se déplacer dans une position qui a déjà été revendiquée. Assurez-vous que la position dans laquelle ils se déplacent n'est pas déjà la cible d'une autre unité, et vous devriez avoir des résultats assez décents.
MichaelHouse
@DeanKnight, je sais comment fonctionnent les comportements de flocage, mais cela régit la façon dont les bots se déplacent du point A au point B, pas le point B.
IceCreamYou
@ Byte56: merci pour le lien. Je ne mets pas littéralement des unités dans des emplacements de grille - dans l'implémentation, il n'y a aucun moyen pour que plusieurs unités soient dirigées vers le même endroit. On dirait que le problème est plus que le tri se confond parfois.
IceCreamYou
1
Une autre idée: Swarm Pathfinding . Dans ce cas, vous ne donneriez pas à chaque unité un point final différent; vous les feriez s'arrêter quand il n'y avait plus de chemin vers le point final (car toutes les autres unités sont sur le chemin), ou ne vous arrêtez pas du tout et laissez la détection de collision faire son travail.
BlueRaja - Danny Pflughoeft

Réponses:

2

Voici mes suggestions sur vos idées:

Tentative 1: pour corriger cette situation, vous pouvez implémenter l'idée "assez proche" évoquée par Spencer. Je ferais quelque chose comme dessiner une bulle autour du point final, qui grandit en fonction d'un rapport entre le nombre et la taille des unités qui s'y trouvent déjà. Supposons que la bulle commence à la taille d'une unité, puis lorsque la première arrive, le rayon double pour les deux unités suivantes, etc.

Tentative 2: un correctif pour celui-ci consisterait à prendre la distance moyenne du groupe les uns par rapport aux autres, puis à réduire la distance des valeurs aberrantes à cela, de sorte que le groupe se retrouve plus groupé qu'il ne l'était à l'origine (la métrique pourrait être plus courte / plus long que la moyenne, tout ce qui le rend décent, ou définissez éventuellement une taille de formulaire maximale basée sur le nombre / la taille des troupes) La seule chose dont vous auriez à vous soucier est lorsque vous modifiez le chemin d'une valeur aberrante, vous '' Je dois vérifier et m'assurer que cela n'interfère pas avec les autres chemins

Tentative 3: vous avez amélioré celle-ci lors de la tentative 4

Tentative 4: Des sons comme celui-ci fonctionneraient bien si vous rencontrez des problèmes. Je recommanderais de jouer avec des spahs autres qu'une simple formation de grille, cependant, pour rendre le mouvement un peu plus naturel, sauf si vous optez pour un réalisme / style militaire, auquel cas il pourrait être intéressant de les avoir "formées" "avant de bouger, mais cela pourrait devenir ennuyeux pour le joueur après un certain temps.

La tentative 4 semble la plus proche de la suppression du comportement de fraisage dans votre problème, mais en termes de maintien du mouvement sans aucun ajustement autre que ce qui est nécessaire, mon préféré serait probablement la tentative 2.

Mais en tant que solution complètement différente, vous pouvez avoir deux types d'objets en ce qui concerne la recherche de chemin; chaque unité, ainsi qu'un objet "escouade" invisible.

Escouade - Vous construisez l'objet escouade au centre du groupe, comme les autres solutions, et utilisez votre orientation pour le diriger vers l'objectif.

Unités - Les unités ignorent complètement le but, et utilisent à la place le pathfinding pour rester à une certaine distance (ou formation, ou toute autre métrique finit par rendre le mouvement le meilleur) de l'objet de l'escouade.

Cela sépare les différents aspects de la recherche de chemin et vous permet de modifier chaque côté isolément pour plus de contrôle sur son apparence.

David M
la source
Très bonne réponse. Merci pour les nouvelles idées. L'approche Squad + Unit est intéressante, nécessite probablement que les unités puissent se déplacer plus rapidement en mode "rattrapage"
IceCreamYou
Oui, une solution consiste à régler la vitesse de déplacement de l'objet "escouade" à un peu en dessous du maximum que les unités individuelles peuvent déplacer, pour leur permettre de se déplacer si nécessaire sans prendre de retard.
David M
2

La tentative 3 pourrait fonctionner, mais elle a besoin d'un peu de raffinement.

Pensez au concept d'une formation (votre grille est un début). Une formation doit avoir un emplacement (c.-à-d. Les coordonnées du clic ou le soldat / bâtiment cible) et une rotation (cela peut être fixe, aléatoire ou déterministe). La formation doit avoir le même nombre de postes que le nombre de soldats sélectionnés.

Un exemple simple de formation peut être un cercle autour de la cible. L'espace se positionne également autour et augmente le rayon du cercle pour s'adapter à tous les soldats sans entrer en collision.

Le problème suivant est de décider quel soldat marche vers quelle position dans la formation. Une solution simple pourrait être d'amener chaque soldat à se déplacer vers la position la plus proche de lui. Si celui-ci est déjà «choisi» par un autre soldat, prenez la prochaine position la plus proche, etc.

Les formations peuvent devenir assez intéressantes. Ci-dessous, une image de la «formation de corne de taureau» utilisée avec grand succès par Shaka le Zoulou . (L'image provient du module de formation TotalWar )

formation de corne de taureau

Willem
la source
"Le prochain problème est de décider quel soldat se rendra à quelle position dans la formation." En fait, c'est tout le problème de cette question. :) A voté pour la suggestion d'une formation de cercle au lieu d'une grille, mais cela est inefficace pour plus de quelques soldats, et le déplacement des soldats vers l'emplacement le plus proche d'eux provoque plus de conflits que ma solution ci-dessus de trier les unités par emplacement.
IceCreamYou
0

Lors du clic de l'utilisateur, tracez un vecteur de chaque soldat à l'emplacement cliqué. Obtenez l'angle vectoriel moyen à partir des vecteurs dessinés pour chaque soldat et déplacez chaque soldat de la longueur de son vecteur individuel dans cette direction avec le même angle. Cela devrait donner l'apparence des unités se déplaçant en formation jusqu'au point et devrait empêcher les unités de s'agglutiner.

Si vous voulez que les unités quittent la formation, vous pouvez pointer l'angle de chaque soldat directement à l'emplacement cliqué. Cependant, sans collision, les unités commenceront à converger. Pour contrer cela, ajoutez une collision et forcez les unités à cesser de bouger une fois qu'elles sont "assez proches" du point cliqué. Les premières unités à arriver seront exactement sur le point et les dernières à arriver devraient être ordonnées d'arrêter de bouger une fois qu'elles sont suffisamment proches ou qu'un certain laps de temps s'est écoulé.

Vous pouvez calculer la longueur du chemin et la vitesse de l'unité pour déterminer quand une seule unité doit arriver, puis forcer l'unité à s'arrêter si elle dépasse ce temps d'une certaine quantité. Vous devrez jouer un peu avec ce numéro.

Spencer
la source
La solution vectorielle que vous proposez est la même que ma tentative 2 ci-dessus. L'une des exigences de cette question est que les unités sélectionnées peuvent ne pas être en formation.
IceCreamYou
Et j'ai écrit sur une solution dans laquelle ils ne bougeraient pas en formation. (2e paragraphe)
Spencer