mercoledì 29 giugno 2011

Nemici che si muovono verso di noi secondo varie traiettorie

Nella realizzazione di uno sparatutto in prima persona (cosiddetti FPS) una delle prime cose da fronteggiare riguarda le modalità con cui gli enemy si avvicineranno a voi. Ad esempio in un videogioco di base horror potremmo avere degli zombi dalla caratteristica camminata "zoppa" che si avvicinano a noi seguendo una determinata traiettoria, del tipo:
  • linea retta;
  • linea curva ("spirale");

Questo almeno è quello che è possibile definire in prima istanza; ora, associando allo zombie uno script di update fatto come segue, regolando i parametri di ingresso delle "velocità" rispetto ad x e a z è possibile di fatto ottenere entrambe le traiettorie.

//walk each to other
var other: GameObject;
var vx = 0.3;
var vz = 0.3;

function walk(){
 animation.CrossFade("zombiewalkcycle");
 
 var p1 = transform.position;
 var p2 = other.transform.position;

 //var tmp = Vector3(0,0,0);

 transform.LookAt(p2); //definisce la direzione
  
 //0.92 vuol dire che si avvicina al punto di molto
 //ad es. 0.50 si avvicina di meno e si stabilizza
 //girandogli attorno
 var xx = (p2.x - p2.x*0.92) * vx;
 var yy = 0;
 var zz = (p2.z - p2.z*0.92) * vz;
 
 transform.Translate(xx, yy, zz, Space.Self);
   
 var d = Vector3.Distance (p1, p2); 
 print ("Distanza tra "+p1+" e "+ p2 +" = "+ d);

}

function Update() {
walk();
}

L'effetto è rappresentato nel seguente video:



Qualche nota di commento sul codice: quello che vi basta cambiare è il valore di vx e vy, che io ho impostato in tre modalità diverse ragionando sugli ordini di grandezza (ricordo che un odg rappresenta, parlando "a spanne", una "decina", per cui da 10 a 1000 vi sono due odg). Per cui ho impostato:

Update nemico per ogni frame:

 var xx = (p.x - p.x*0.92) * vx;
 var zz = (p.z - p.z*0.92) * vz;

dove ho testato tre possibilità:
1) vx=vy=0.05 spirale 1
2) vx=0.5, vy=0.05 spirale 2
3) vx=0.05, vy=0.5 linea "quasi" retta

Ovviamente il tutto è completamente indipendente, da quanto ho sperimentato, dalla posizione relativa dei due oggetti: il funzionamento si basa sul fatto che l'oggetto che si muove (lo zombie, per capirci) calcola il proprio forward "guardando" nella direzione del target (il vostro player, ovvero quello che nel video resta fermo). L'algoritmo, regolando opportunamente la velocità, converge anche se il player-target si muove nel tempo, e gli inizierà presto a girare intorno, mantenendo uan distanza costante che dipende dallo 0.92 che ho lasciato nel codice:

//0.92 vuol dire che si avvicina al punto di molto
 //ad es. 0.50 si avvicina di meno e si stabilizza
 //girandogli attorno
 var xx = (p2.x - p2.x*0.92) * vx;
 var yy = 0;
 var zz = (p2.z - p2.z*0.92) * vz;

Qualsiasi osservazione a riguardo nei commenti: spero che la cosa possa essere utile per qualcuno di voi.