Che tipo di comportamento di governo o logica posso usare per far circondare i cellulari a un altro?


10

Sto usando la ricerca del percorso nel mio gioco per guidare un mob verso un altro giocatore (per inseguirlo). Questo funziona per farli superare il giocatore, ma voglio che si fermino leggermente prima della loro destinazione (quindi scegliere il penultimo nodo funziona bene).

Tuttavia, quando più mob inseguono il cellulare, a volte "si accumulano uno sopra l'altro". Qual è il modo migliore per evitarlo? Non voglio trattare i mob come opachi e bloccati (perché non lo sono, puoi percorrerli) ma voglio che i mob abbiano un senso della struttura.

Esempio:

Immagina che ogni serpente si sia guidato da me e debba circondare "Setsuna". Notate come entrambi i serpenti hanno scelto di potarmi? Questo non è un requisito rigoroso; anche essere leggermente sfalsato va bene. Ma dovrebbero "circondare" Setsuna.

inserisci qui la descrizione dell'immagine


1
L'accatastamento è solo un problema a destinazione o anche durante il trasporto? Sto indovinando quest'ultimo.
SpartanDonut,

È quest'ultimo, @SpartanDonut
Vaughan Hilts, il

@KromStern Ho aggiunto una foto, spero che sia di aiuto.
Vaughan Hilts,

Risposte:


15

Dai ai tuoi agenti una debole "carica elettrostatica" per farli respingere a vicenda, secondo la legge di Coulomb .

Supponendo per semplicità che i mob dovrebbero allontanarsi a vicenda con forza equivalente, dovrebbe essere sufficiente applicare una forza tra ogni coppia di mob con una grandezza some_constant / distance^2, dove some_constantc'è una forza di repulsione configurabile ed distanceè la distanza che li separa.

Le forze di repulsione cadono quindi con il quadrato della distanza.

Nature of Code ha un ottimo esempio (con una demo live) qui . Sembra così:

comportamenti seguiti e separati combinati

Far corrispondere ogni elemento l'uno contro l'altro è un'operazione quadratic-time ( O(n^2)). Se hai davvero molti agenti, potresti voler ottimizzare i calcoli della forza con un'approssimazione di Barnes-Hut , che lo porta a log-linear ( O(n log n)) ma richiede un quadrifoglio .


Ottimo collegamento, Anko. Molto apprezzato! Dovrò sicuramente dare a questo intero sito una lettura.
Vaughan Hilts,

Starcraft (almeno 1) fa qualcosa di simile con le sue unità volanti. Ma lo fa solo quando smettono di muoversi, cioè quando sono in movimento si aggregano l'uno sull'altro (ignorandosi completamente come ostacoli), ma quando si fermano iniziano tutti a diffondersi da quello che sembra essere il centro locale di un'area regolare (quadrata / cerchio, probabilmente) che li comprende. Questo non sembra carino come nell'esempio nella risposta, ma probabilmente utilizza meno risorse della CPU, ed è forse anche più facile da programmare ...
Shivan Dragon

@ShivanDragon SC2 presenta lo stesso comportamento, convergono tutti verso la destinazione in mezzo alla folla, quindi spaziano per un aspetto un po 'realistico e esteticamente piacevole (quindi le loro parti non si aggirano).
Kroltan,

2
Un qualche tipo di forza repellente può essere una buona idea, ma i dettagli sono difficili. Li ho sperimentati in un RTS a tema spaziale e consiglio di non seguire la fisica troppo da vicino e piuttosto di modellarla in modo che si comporti bene. Alcune osservazioni: 1) Dato che questa non è una simulazione fisica, applicherei la forza solo su brevi distanze. 2) Ciò non può impedire la sovrapposizione di corpi finiti. 3) Il potenziale difficile causa facilmente errori numerici, come le particelle che vengono rifratte ad alta velocità. 4) Una volta che hai un numero significativo di particelle e pressione nel mezzo aumenta, le cose tendono a diventare brutte.
CodesInCos

1

Il mio approccio è simile a quello di @ Anko, ma basato sul lavoro di Millington e Funge di Artificial Intelligence for Games .

Questo è l'aspetto di un comportamento di Separazione, ma è necessario tenere presente che questa velocità deve essere calcolata con la velocità dell'agente nella sua funzione di aggiornamento.

public Vector3 GetSeparationVel (float threshold, float decayCoefficient)
{
    threshold = threshold * threshold;
    Vector3 separationVelocity = Vector3.Zero;
    for (int i = 0; i < enemies.Length; i++) {
        if (enemies[i] == this) {
            continue;
        }
        Vector3 direction = this.position - enemies[i].position;
        float distance = direction.LengthSquared();
        float strenght = 0.0f;
        if (distance < (threshold)) {
            strenght = Math.Min(decayCoefficient / distance, this.maxAccel);
            direction.Normalize();
            separationVelocity += strenght * direction;
        }
    }
}
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.