Determinazione della posizione finale per il movimento dell'IA in gruppi in un RTS 2D


8

Ho scritto un gioco RTS (una demo per una sorta di motore di gioco, in realtà) in cui l'interazione di base dell'utente con il gioco consiste nel selezionare un gruppo di soldati e quindi fare clic con il tasto destro sulla mappa per spostarli nella posizione specificata. Questo è in JavaScript e puoi giocarci qui ( codice ).

Ignorando il problema di come i soldati si spostano dalla loro posizione attuale alla loro destinazione, la mia domanda riguarda la determinazione di quale sia la loro destinazione effettiva. Ecco cosa ho provato finora:

  • Tentativo 1: dire a tutti i soldati selezionati di spostarsi sulle coordinate su cui ha fatto clic il mouse. Questo ha lo strano comportamento che tutti i soldati si raggrupperanno in modo innaturale attorno al bersaglio.
  • Tentativo 2: trova le coordinate medie di tutti i soldati selezionati, quindi trova l'offset da quel punto centrale per ciascun soldato e infine traduci l'offset attorno alle coordinate del mouse. Funziona bene, tranne per il fatto che se i tuoi soldati selezionati sono molto distanti non si avvicinano al bersaglio.
  • Tentativo 3: costruisci una griglia attorno alle coordinate del mouse e posiziona ciascun soldato selezionato in una cella della griglia. Se ogni soldato arriva alla cella assegnata, questo funziona alla grande. Tuttavia, i soldati sono assegnati alle celle della griglia nell'ordine in cui sono stati generati, quindi a volte si scontrano (cioè tutti i soldati sul lato destro cercheranno di andare sul lato sinistro) che sembra innaturale.
  • Tentativo 4: usa una griglia come prima, ma prima ordina i soldati per posizione in modo che si allineino in modo sensato, cioè se fai clic sotto il gruppo, i soldati nella parte inferiore del gruppo finiranno nella parte inferiore della griglia quando raggiungere la loro destinazione. Funziona piuttosto bene ma a volte ci sono problemi e non sono sicuro del perché.

Ecco la funzione che determina le coordinate di destinazione:

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

Puoi incollare questa funzione nella console JavaScript del tuo browser quando visualizzi la demo e scherzi con essa per cambiare il comportamento dei soldati.

La mia domanda è: esiste un modo migliore per determinare la posizione di destinazione in cui ogni soldato deve spostarsi?


Qualcosa chiamato "floccaggio" può essere molto utile per te e può fornirti il ​​tipo di funzionalità che stai cercando. Prova: processing.org/examples/flocking.html o semplicemente "floccaggio" di Google o "Boids". Questo potrebbe metterti nella giusta direzione.
Dean Knight,

2
Correlati: gamedev.stackexchange.com/questions/44361 Direi che i "glitch" che stai vivendo provengono da unità che stanno provando a spostarsi in una posizione che è già stata rivendicata. Assicurati che la posizione in cui si stanno spostando non sia già l'obiettivo di un'altra unità e dovresti avere risultati abbastanza decenti.
MichaelHouse

@DeanKnight, sono consapevole di come funzionano i comportamenti di floccaggio, ma questo regola il modo in cui i robot ottengono dal punto A al punto B, non quale sia il punto B.
IceCreamYou

@ Byte56: grazie per il link. Non sto letteralmente mettendo le unità negli slot della griglia: nell'implementazione non è possibile indirizzare più unità nello stesso punto. Sembra che il problema sia più che l'ordinamento a volte viene confuso.
IceCreamYou,

1
Un'altra idea: Swarm Pathfinding . In questo caso, non daresti ad ogni unità un punto finale diverso; li fermeresti solo quando non restava alcun percorso verso l'endpoint (perché tutte le altre unità sono in mezzo), oppure non fermarti affatto e lasciare che il rilevamento delle collisioni faccia il suo lavoro.
BlueRaja - Danny Pflughoeft il

Risposte:


2

Ecco i miei suggerimenti sulle tue idee:

Tentativo 1: per risolvere questa situazione, è possibile implementare l'idea "abbastanza vicina" sollevata da Spencer. Vorrei fare qualcosa come disegnare una bolla attorno al punto finale, che cresce in base a un rapporto tra il numero e la dimensione delle unità già presenti. Supponiamo che la bolla inizi la dimensione di un'unità, quindi quando arriva la prima, il raggio raddoppia per le due unità successive, ecc.

Tentativo 2: una correzione per questo, sarebbe prendere la distanza media del gruppo l'uno dall'altro, quindi tagliare la distanza dei valori anomali a quello, in modo che il gruppo finisca più raggruppato di quello che erano originariamente (la metrica potrebbe essere più breve / più lungo della media, qualunque cosa lo faccia sembrare decente o eventualmente impostare una dimensione massima del modulo in base al numero / dimensione delle truppe di nuovo) L'unica cosa di cui dovresti preoccuparti è quando modifichi il percorso di un outlier, tu " devo controllare e assicurarsi che non interferisca con gli altri percorsi

Tentativo 3: è stato migliorato nel tentativo 4

Tentativo 4: sembra che questo funzionerebbe benissimo se trovi qualsiasi problema tecnico lo stia eliminando. Consiglierei di giocare con spahes diversi dalla semplice formazione di una griglia, tuttavia, per rendere il movimento un po 'più naturale, a meno che tu non stia cercando uno stile realistico / militare, nel qual caso potrebbe essere pulito averli "formati "prima di spostarsi, ma dopo un po 'potrebbe diventare fastidioso per il giocatore.

Il tentativo 4 sembra il più vicino alla rimozione del comportamento di fresatura nel tuo problema, ma in termini di mantenere il movimento scorrevole senza alcuna regolazione diversa da quella necessaria, il mio preferito sarebbe probabilmente il tentativo 2.

Ma come soluzione completamente diversa, puoi avere due tipi di oggetti quando si tratta di pathfinding; ogni unità, così come un oggetto "squadra" invisibile.

Squadra: costruisci l'oggetto squadra al centro del gruppo, come le altre soluzioni, e usi il tuo percorso per indirizzarlo verso l'obiettivo.

Unità: le unità ignorano del tutto l'obiettivo e usano invece l'individuazione del percorso per mantenersi a una certa distanza (o formazione, o qualsiasi altra metrica finisce per rendere il movimento migliore) dall'oggetto squadra.

Ciò separa i diversi aspetti del pathfinding e consente di modificare entrambi i lati in modo isolato per un maggiore controllo sull'aspetto.


Bella risposta. Grazie per le nuove idee. L'approccio Squad + Unit è interessante, probabilmente richiede che le unità possano muoversi più velocemente in modalità "catch-up"
IceCreamYou

Sì, una soluzione è quella di impostare la velocità di movimento dell'oggetto "squadra" su un po 'al di sotto del massimo che le singole unità possono muovere, per consentire loro di spostarsi se necessario senza restare indietro.
David M,

2

Il tentativo 3 potrebbe funzionare, ma ha bisogno di un po 'di raffinatezza.

Pensa al concetto di formazione (la tua griglia è un inizio). Una formazione dovrebbe avere una posizione (cioè le coordinate dei clic, o il soldato / edificio target) e una rotazione (questa potrebbe essere fissa, casuale o deterministica). La formazione deve avere lo stesso numero di posizioni del numero di soldati selezionati.

Una semplice formazione di esempio può essere un cerchio attorno al bersaglio. Lo spazio si posiziona equamente intorno e aumenta il raggio del cerchio per adattarsi a tutti i soldati senza scontrarsi.

Il prossimo problema è decidere quale soldato cammina in quale posizione nella formazione. Una soluzione semplice potrebbe essere quella di far spostare ogni soldato nella posizione più vicina a lui. Se quello è già "scelto" da un altro soldato, prendi la prossima posizione più vicina, ecc.

Le formazioni possono diventare piuttosto interessanti. Di seguito un'immagine della "formazione del corno di toro" usata con grande successo da Shaka lo Zulu . (L'immagine proviene dalla mod di formazione TotalWar )

formazione del corno di toro


"Il prossimo problema è decidere quale soldato cammina in quale posizione nella formazione." In realtà, questo è l'intero problema di questa domanda. :) È stato votato per il suggerimento di una formazione circolare anziché una griglia, ma questo è inefficace per più di alcuni soldati, e spostare i soldati nella posizione più vicina a loro causa più conflitti della mia soluzione sopra di ordinare le unità per posizione.
IceCreamYou,

0

Al clic dell'utente, disegna un vettore da ogni soldato nella posizione cliccata. Prendi l'angolo vettoriale medio dai vettori disegnati per ciascun soldato e sposta ciascun soldato per la lunghezza del suo singolo vettore in quella direzione con lo stesso angolo. Ciò dovrebbe dare l'aspetto delle unità che si muovono in formazione verso il punto e impedire alle unità di aggregarsi.

Se vuoi che le unità si spostino fuori formazione, puoi puntare l'angolo di ogni soldato direttamente nella posizione cliccata. Tuttavia, senza collisione le unità inizieranno a convergere. Per contrastare ciò, aggiungi una collisione e forza le unità a smettere di muoversi una volta che sono "abbastanza vicine" al punto cliccato. Le prime unità in arrivo saranno esattamente sul punto e le ultime in arrivo dovrebbero essere indirizzate a smettere di muoversi una volta che sono abbastanza vicine o è trascorso un certo periodo di tempo.

È possibile calcolare la lunghezza del percorso e la velocità dell'unità per determinare quando una singola unità dovrebbe arrivare e quindi forzare l'unità a smettere di muoversi se supera tale tempo di un determinato importo. Dovrai giocare un po 'con quel numero.


La soluzione vettoriale che stai suggerendo è la stessa del mio tentativo 2 sopra. Uno dei requisiti di questa domanda è che le unità selezionate potrebbero non essere in una formazione.
IceCreamYou,

E ho scritto di una soluzione in cui non si sarebbero mossi in formazione. (2o paragrafo)
Spencer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.