Nel mondo naturale, gli organismi mostrano determinati comportamenti quando viaggiano in gruppo. Questo fenomeno, noto anche come affollando, si verifica sia su bilance microscopiche (batteri) che su squame macroscopiche (pesci). Utilizzando i computer, questi modelli possono essere simulati creando semplici regole e combinandole. Questo è noto come comportamento emergente, e può essere utilizzato nei giochi per simulare movimenti di gruppo caotici o reali.
Nota: Sebbene questo tutorial sia stato scritto usando Flash e AS3, dovresti essere in grado di utilizzare le stesse tecniche e concetti in quasi tutti gli ambienti di sviluppo di giochi.
In questo tutorial, tratterò le tre principali regole utilizzate per simulare il floccaggio e spiegare come implementare ciascuna di esse. Prima di iniziare, ecco una terminologia che userò:
Questa demo mostra gli effetti delle tre regole di floccaggio che spiegherò in questo tutorial: allineamento, coesione, e separazione.
Il codice sorgente completo per questa demo può essere scaricato qui, quindi questo articolo evidenzierà solo gli aspetti più importanti dell'implementazione. Sentiti libero di scaricare la fonte se desideri saperne di più.
L'allineamento è un comportamento che fa in modo che un determinato agente si allinei con gli agenti nelle vicinanze.
Innanzitutto, creeremo una funzione che accetta un agente e restituisce un vettore di velocità.
funzione pubblica computeAlignment (myAgent: Agent): Point
Avremo bisogno di due variabili: una per memorizzare il vettore che calcoleremo e un'altra per tenere traccia del numero di vicini dell'agente.
var v: Point = new Point (); var neighborCount = 0;
Con le nostre variabili inizializzate, ora iteriamo attraverso tutti gli agenti e troviamo quelli all'interno di raggio vicino - cioè, quelli abbastanza vicini da essere considerati vicini dell'agente specificato. Se si trova un agente all'interno del raggio, la sua velocità viene aggiunta al vettore di calcolo e il conteggio dei vicini viene incrementato.
per ogni (agente var: Agent in agentArray) if (agent! = myAgent) if (myAgent.distanceFrom (agent) < 300) v.x += agent.velocity.x; v.y += agent.velocity.y; neighborCount++;
Se non sono stati trovati vicini, restituiamo semplicemente il vettore zero (il valore predefinito del vettore di calcolo).
if (neighborCount == 0) restituisce v;
Infine, dividiamo il vettore di calcolo per il conteggio dei vicini e lo normalizziamo (dividilo per la sua lunghezza per ottenere un vettore di lunghezza 1
), ottenendo il vettore risultante finale.
v.x / = neighborCount; v.y / = neighborCount; v.normalize (1); return v;
La coesione è un comportamento che induce gli agenti a orientarsi verso il "centro di massa", cioè la posizione media degli agenti entro un certo raggio.
L'implementazione è quasi identica a quella del comportamento di allineamento, ma ci sono alcune differenze chiave. Innanzitutto, invece di aggiungere il velocità al vettore di calcolo, il posizione viene invece aggiunto.
v.x + = agent.x; v.y + = agent.y;
Come in precedenza, il vettore di calcolo è diviso per il conteggio dei vicini, risultante nella posizione corrispondente al centro di massa. Tuttavia, non vogliamo il centro di massa stesso, vogliamo la direzione in direzione il centro di massa, quindi ricalcolo il vettore come distanza dall'agente al centro di massa. Infine, questo valore è normalizzato e restituito.
v.x / = neighborCount; v.y / = neighborCount; v = new point (v.x - myAgent.x, v.y - myAgent.y); v.normalize (1); return v;
La separazione è il comportamento che induce un agente a deviare da tutti i suoi vicini.
L'implementazione della separazione è molto simile a quella dell'allineamento e della coesione, quindi indicherò solo cosa è diverso. Quando viene trovato un agente adiacente, la distanza dall'agente al vicino viene aggiunta al vettore di calcolo.
v.x + = agent.x - myAgent.x; v.y + = agent.y - myAgent.y
Il vettore di calcolo è diviso per il conteggio del vicino corrispondente, ma prima di normalizzarsi, c'è un altro passaggio cruciale. Il vettore calcolato deve essere negato per consentire all'agente di allontanarsi correttamente dai suoi vicini.
v.x * = -1; v.y * = -1;
Una volta che queste tre regole sono state implementate, hanno bisogno di venire insieme. Il modo più semplice per farlo è il seguente:
var alignment = computeAlignment (agent); coesione var = computeCohesion (agente); var separation = computeSeparation (agent); agent.velocity.x + = alignment.x + cohesion.x + separation.x; agent.velocity.y + = alignment.y + cohesion.y + separation.y; agent.velocity.normalize (AGENT_SPEED);
Qui, calcolo semplicemente le tre regole per un particolare agente e le aggiungo alla velocità. Poi normalizzo la velocità e poi moltiplico per qualche costante che rappresenta la velocità predefinita per un agente. È possibile potenziarlo ulteriormente aggiungendo pesi per ogni regola per modificare i comportamenti:
agent.velocity.x + = alignment.x * alignmentWeight + cohesion.x * cohesionWeight + separation.x * separationWeight; agent.velocity.y + = alignment.y * alignmentWeight + cohesion.y * cohesionWeight + separation.y * separationWeight;
La modifica di questi pesi cambierà il modo in cui gli agenti si affollano. Assicurati di sperimentare con i numeri finché non trovi qualcosa che ti piace.
Ecco di nuovo la demo per provarla:
Flocking è semplice da implementare, ma ha alcuni risultati potenti. Se stai facendo un gioco con l'intelligenza artificiale, specialmente i grandi gruppi di intelligenza artificiale che interagiscono tra loro, il floccaggio potrebbe tornare utile. Usalo bene.