In questo articolo vedrai com’è possibile creare una gerarchia per inserire nei tasselli dell’ambiente di gioco vari oggetti sia statici che dinamici (nemici). La base di questa parte della serie è fondamentalmente legata alla parentela tra gli oggetti, il tassello (piano o se vuoi chiamarlo pezzo della mappa) è il genitore e a lui verranno imparentate delle empty che richiameranno gli oggetti che servono a formare l’ambiente di gioco. Per questo tutorial ho creato un file apposito che puoi scaricare QUA.
Prima di iniziare con il tutorial ti spiego in breve cosa trovi nel file che hai appena scaricato, ti ricordo che puoi anche usare un tuo file l’importante che abbia quattro oggetti per ogni tipo (che è il minimo richiesto per una buona randomizzazione).
Nel layer 1 hai la scena di gioco, puoi muovere il player con il mouse e col tasto sinistro farlo andare avanti.
Nel layer 2 ci sono i tasselli della mappa, lavorerai principalmente su questo layer.
Nel layer 3 ci sono i nemici e una serie di oggetti che vedremo nel dettaglio nella seconda parte di quest’articolo.
Nel layer 4 ho inserito degli oggetti statici, partiremo da loro per creare la base per farti capire al meglio questa tecnica.
Oggetti statici
Come ho detto sopra lavorerai principalmente sul secondo layer, se hai già letto il primo articolo di questa serie saprai come implementare una randomizzazione per i tasselli della mappa, se non l’hai letto ti consiglio di farlo, trovi il link sulla destra tra gli articoli recenti. Come prima cosa inserisci una Empty, questa volta basta una semplice Plane Axis, prima di imparentarla crea la logica per la randomizzazione degli oggetti, la procedura è uguale a quella dei tasselli della mappa.
Rinomina la Empty, è una buona abitudine farlo sempre prima, dare un nome a ogni oggetto che sia inerente al suo compito (non mi stancherò mai di scriverlo perché è una cosa importante), io l’ho chiamata obj_spawn. Inserisci una Property int e chiamala random (o come meglio credi), inserisci un Sensor Always e clicca sul Tap, inserisci un’Actuator Random, cambia la Distirb a Int Uniform e assegnala alla Property precedentemente creata, digita su Min 1 e Max 4, collega i due Mattoni con un Controller And. Per controllare se questa linea di Mattoni funziona metti la Property in Debug Mode e fai partire il motore diverse volte. Adesso puoi inserire gli oggetti di scena del layer 4, uno per ogni numero della randomizzazione della Property. Inserisci un Sensor Property, sul campo Property scegli l’unica che è nella lista, come Value (valore) inserisci 1, adesso aggiungi un’Actuator Edit Object e senza cambiare nulla scegli nel campo Object l’oggetto obj_1, collega i due Mattoni tramite un Controller And. Ripeti questa procedura per tutti gl’altri oggetti.
Il prossimo passo è quello di imparentare la Empty con uno dei tasselli, puoi anche duplicarla per avere più oggetti sullo stesso tassello, questo dipende da te. Io imparento la Empty al tassello di colore rosa, una volta imparentato lo puoi spostare nella posizione che preferisci, quando sei soddisfatto salva e prova il file dal primo layer. Come puoi notare quando appare il tassello rosa viene randomizzato lo spawn di uno degli oggetti del layer 4 esattamente nel punto dove si trova la Empty, lo stesso se l’hai duplicata e spostata in varie posizioni o in altri tasselli, ricorda che se vuoi fare apparire un oggetto in un altro tassello devi imparentare la Empty a quel tassello. Naturalmente più oggetti hai più il terreno sarà variegato.
Oggetti dinamici
Allo stesso modo è possibile inserire degli oggetti dinamici come ad esempio dei nemici, la procedura è identica. Ho creato dei nemici che si muovono tra due nodi in modo da farti vedere come si possono fare spawnare diversi oggetti usando una gerarchia a partire da una sola Empty. Se vai al layer 3 puoi notare che i nodi su cui si muovono due dell’enemy sono imparentati tra loro, questo per evitare di inserire più Empty, e vi sono due Empty (spa_enemy0 e spa_enemy1) con altrettante Empty imparentate ad esse (in forma di Single Arrow), questa è una gerarchia, forse questa parte può crearti un po’ di confusione in testa, ma credimi che è più semplice di come sembra. Enemy_3 ed enemy_2 hanno un Trigger attorno a loro, il Trigger è un’oggetto invisibile che innesca una procedura al contatto con un’oggetto in questo caso fa scattare l’inseguimento quando il player lo tocca; questa procedura, con il Trigger, invece che con un Sensor Near o un Radar riduce il carico del motore di gioco perché i due Sensors citati aumentano notevolmente l’impatto con la fisica, mentre il Trigger invia un messaggio all’oggetto interessato e poi scompare. L’unico problema di questo sistema è che quando nel gioco appaiono due oggetti dello stesso tipo il messaggio viene inviato a tutti gli oggetti di quel tipo, in questo modo inizierà l’inseguimento anche se il player non è entrato in contatto con il Trigger, l’unico modo di evitarlo è via Python script, ma non è questo l’argomento di questo tutorial.
La teoria è che la Empty sul tassello crea la Empty genitore sopra citate, in questo modo quando parte il gioco i genitori creano i nemici e i nodi in automatico.
A questo punto puoi seguire due strade, la prima è aumentare i numeri da randomizzare delle Empty già esistenti aggiungendo poi altri mattoni e facendo spawnare i nemici negli stessi punti degli oggetti statici (con un fattore di 8 interi la possibilità che ci sia un nemico a ogni avvio è ridotta), oppure aggiungere un’altra Empty che spawni solo i nemici in questo modo sei sicuro che ci sia uno dei nemici ad ogni avvio del gioco. Penso che la seconda sia la più adatta perché è ovvio che in un gioco, a parte alcune tipologie, ci siano dei nemici. La procedura è la stessa di quella precedente, solo che nel caso dei due nemici, enemy0 ed enemy1, invece di inserire direttamente gli oggetti nel campo dell’Actuator Edit Object bisogna inserire la Empty sopra citata. Mentre per i due nemici con il Trigger non è un problema perché sono genitori diretti del Trigger.
Inserisci sul layer 2 una nuova Empty ed esegui la stessa procedura di prima creando prima una Property da randomizzare, e poi accoppiando ogni enemy al numero della Property, ricorda che per i due nemici (enemy0 ed enemy1) devi indicare sull’Actuator Edit Object le Empty spa_enemy0 e spw_enemy1. Imparenta poi la Empty, che io ho chiamato enemy_spawner ad uno dei tasselli, essendo un esempio non è perfetto al 100%, quindi fai bene attenzione al movimento che i due nemici fanno, uno è orizzontale e l’altro verticale, questo ti farà capire dove posizionare la Empty in modo da evitare brutti movimenti. Non ho scritto la procedura passo passo perché sarebbe come ripetere sempre le stesse cose.
Alcune consigli utili
Come avrai capito è possibile concatenare i vari oggetti, sia statici che dinamici, in modo che facciano parte di una gerarchia ben precisa per poi farli spawnare nella mappa come meglio credi usando una sola Empty, questo è motlo utile se si vuole, per esempio, creare un sentiero in mezzo a degli alberi, non devi fare altro che impostare gli alberi nel percorso che vuoi, poi spostarli su un’altro layer e imparentarli ad una Empty che verrà richiamata da un’altra Empty posta sul tassello di gioco, bisogna anche modellare i vari alberi e si può anche creare una gerarchia che randomizzi gli alberi usando delle Empty Singol Arrow per ogni posizione dove si vogliono fare apparire i vari tipi di albero. Naturalmente questo è solo un’esempio, ma questa tecnica non ha limiti, basti pensare che modellando una quantità di oggetti si può avere un gioco diverso ad ogni avvio, oppure, man mano si va avanti il gioco spawni sempre oggetti diversi nella scena. Come sempre sta a te creare il giusto bilanciamento tra le parti.
Cerca di sperimentare il più possibile, prova all’inizio con le primitive e poi usa questa tecnica in un gioco, anche solo per capire come si integra in un prodotto finale. Fin’ora hai visto come usare i Mattoni, ma se hai un numero notevole di oggetti potrebbe essere tedioso aggiungere mattoni su mattoni, nel prossimo tutorial vedrai come viene semplificata questa procedura via Python script. Buon divertimento.