Maze games

MAZE GAMESTratto da: Game Maker Tutorial – Creating Maze Games – Written by Mark Overmars – Copyright © 2007-2009 YoYo Games Ltd
www.yoyogames.com/…/maze.zip

I giochi di labirinto sono una categoria di videogioco molto popolare e sono semplici da realizzare con GameMaker.

Questo tutorial ti spiega in pochi semplici passi come realizzare un gioco di questo tipo.
La parte divertente è che dal primo passo in poi abbiamo un gioco vero che, passo dopo passo, diventa sempre più esteso e attraente.

 

Quale gioco?

Prima di iniziare con la realizzazione del gioco dobbiamo arrivare a un’idea chiara su quale gioco vogliamo realizzare.
Questo è il passo più importante (e in qualche senso il più difficile) nella realizzazione di un gioco.
Un buon gioco è eccitante, sorprendente e coinvolgente.
Ci devono essere obbiettivi chiari per il giocatore e l’interfaccia grafica deve essere intuitiva.

Il gioco che stiamo per realizzare è un gioco di labirinto.
Ciascun livello è un labirinto.
Per uscire dal labirinto dobbiamo raccogliere tutti i diamanti e poi raggiungere l’uscita.
Per fare questo il giocatore deve risolvere degli enigmi ed evitare dei mostri.

Gli enigmi potrebbero essere

  • dei blocchi devono essere spinti dentro delle buche
  • parti del muro possono esplodere utilizzando delle bombe

È molto importante non rivelare tutto nel primo livello.
I nuovi oggetti, e i mostri, dovrebbero apparire gradualmente per rendere il gioco interessante.

Allora

  • L’oggetto principale è una persona controllata dal giocatore.
  • Ci sono muri (potrebbero essere di diverso tipo per rendere il labirinto più piacevole).
  • Ci sono diamanti da raccogliere.
  • Ci sono in giro degli oggetti che fanno qualcosa se toccati o raccolti dal giocatore.
  • Un oggetto particolare sarà l’uscita dal livello.
  • E ci sono dei mostri che si muovono da soli.

Ma trattiamo tutto un passo alla volta.

Tutti i giochi parziali sono forniti nella cartella Examples inclusa nel tutorial e possono essere caricati in GameMaker.
Sono fornite anche tutte le risorse nella cartella Resources.

Person Wall Goal Wall Wall Wall Door Diamond Mostro 1 Mostro 2 Mostro 3 Blocco Buca Bomba Detonatore Person Mostro 1 Mostro 2

Mostro 3 Bonus 1 Bonus 2 Bonus 3 Move Up Move Right Move Down Move Left

 

Un semplice inizio

Come primo passo dimentichiamoci dei diamanti.
Creeremo un gioco nel quale il giocatore deve semplicemente raggiungere l’uscita.

Ci sono 3 ingredienti fondamentali nel gioco: il giocatore, ilmuro e la meta.
Per ognuno di essi sono necessari una sprite e un oggetto.

Gli oggetti

Come primo passo creiamo gli oggetti.
Per ognuno dei 3 oggetti utilizziamo una semplice immagine 32x32.
Crea le 3 sprite e dagli i nomi spr_personspr_wall e spr_goal.
Il personaggio e la meta devono essere trasparenti.
Il muro non deve essere trasparente.
Adesso creiamo i 3 oggetti.

WallCominciamo con la realizzazione del muro.
Gli assegniamo la sprite spr_wall come immagine, lo nominiamo obj_wall, selezioniamo la casella Solid per indicare che il muro è solido.
In questo modo gli altri personaggi non potranno attraversarlo.
L’oggetto muro non fa altro.
Quindi non c’è bisogno di definire alcun evento per esso.

GoalPassiamo alla realizzazione dell’oggetto meta.
Questo è l’oggetto che il giocatore deve raggiungere.
Non è un oggetto solido.
Abbiamo deciso, momentaneamente, di assegnarli come figura una bandiera a schacchi.
Questo rende chiaro al giocatore che deve raggiungerla.
Quando il personaggio la tocca dobbiamo passare al prossimo livello.
Quindi aggiungiamo questa azione Next Room nell’evento collisione Collision Event (si trova nella scheda main1).
Quest’azione ha delle controindicazioni.
Provoca un errore quando il giocatore ha finito l’ultimo livello.

Dobbiamo quindi fare qualcosa:

  1. prima controlliamo se c’è un altro livello If Next Room
  2. se è vero ci andiamo Next Room
  3. altrimenti Else Action
  4. facciamo ripartire il gioco Restart Game.
obj_goal

Naturalmente, nel gioco completo faremo qualcosa di più quando il giocatore completa l’ultimo livello, come visualizzare un’immagine carina, oppure assegnargli un posto nella classifica dei giocatori più bravi.
Riprenderemo la cosa più avanti.

PersonInfine realizziamo il personaggio controllato dal giocatore.

Per questo serve del lavoro in più.
Deve reagire alle azioni dell’utente e non deve sbattere sui muri.
Utilizzeremo le frecce direzionali per il movimento.
Questo è naturale, quindi facile per l’utente.
Ci diversi modi per far muovere un personaggio

  1. Il modo più semplice è spostare il personaggio di una cella nella direzione indicata dal giocatore premendo una freccia.
  2. Una seconda possibilità, che noi utilizzeremo, è che il personaggio continui a muoversi in una direzione finché il tasto è premuto.
  3. Un altro approccio prevede che il personaggio continui a muoversi finché non viene premuto un altro tasto (come inPacMan).

Sono necessarie delle azioni per le 4 frecce direzionali.
Si tratta di azioni piuttosto banali.
Semplicemente impostano la giusta direzione per il movimento (come speed utilizziamo 4).
Per fermarci, quando il giocatore rilascia il tasto, utilizziamo l’evento Keyboard con il valore <no key>.
In questo evento fermiamo il movimento.
Purtroppo c’è una complicazione.
Vogliamo che il personaggio si trovi allineato con le celle della griglia che forma il labirinto.
Altrimenti il movimento diventerebbe piuttosto difficile.
Cioè vogliamo che si fermi nella posizione giusta per passare in un corridoio.
Si ottiene come segue.
Nella scheda control c’è un’azione If Grid per controllare se l’istanza dell’oggetto è allineata alla griglia.
Solamente se questo è vero verrà eseguita la prossima azione.

Check GridAggiungiamola a ogni evento delle frecce direzionali e impostiamo i parametri snap a32 che è la dimensione della griglia nel nostro labirinto:

 Chiaramente è necessario anche fermare il movimento quando si finisce sul muro.
Quindi nell’evento collisione del personaggio con il muro inseriamo un’azione che ferma il movimento.

C’è un problema che devi valutare a questo punto.
Se la sprite del personaggio non riempie completamente la cella, che è la normalità, potrebbe accadere che il personaggio non sia allineato alla griglia quando collide con il muro.
Per precisione, succede quando c’è un bordo di dimensione maggiore della velocità intorno all’immagine.
In questo caso il personaggio rimarrà immobile perché non reagirà ai tasti (perché non è allineato alla griglia) ma non potrà nemmeno muoversi in avanti (perché c’è il muro).
La soluzione è rendere la sprite più grande oppure disabilitare Precise collision checking e specificare Full image comeBounding box.

I livelli

Questo è tutto quello che dovevamo per le azioni.
Adesso realizziamo alcuni livelli.
Crea 1 o 2 livelli che assomiglino a un labirinto.
In ogni livello posiziona l’0ggetto meta come destinazione e un oggetto personaggio alla posizione di partenza.

Finito!

E questo è tutto, il primo gioco è pronto.
Giocaci per un po’ e prova a fare delle modifiche, per esempio

  • cambia la velocità del personaggio nel suo evento Create
  • crea dei nuovi livelli
  • cambia le immagini

 

 Raccogliere i diamanti

Ma l’obiettivo del nostro gioco non era raccogliere i diamanti?

I diamanti sono oggetti piuttosto semplici.
Ma come facciamo a essere sicuri che il giocatore non possa uscire dal livello finché non ha raccolto tutti i diamanti?
Per questo aggiungiamo un oggetto porta.
L’oggetto porta si comporterà come un muro finché ci saranno diamanti in giro e si dissolverà quando saranno spariti tutti i diamanti.

Oltre agli oggetti muro, meta e personaggio adesso sono necessari altri due oggetti con le sprite corrispondenti: il diamante e la porta.

DiamondIl diamante è un oggetto semplicissimo.
Ha bisogno di una sola azione che lo distrugga quando collide con il personaggio.
Allora aggiungiamo un’azione Destroy nell’evento di collisione.

Door 2L’oggetto porta sarà piazzato in posizione cruciale per bloccare il passaggio verso la meta.
Sarà Solid (per bloccare il passaggio al personaggio).
Nell’evento collisione della persona con la porta dobbiamo fermare il movimento.

Nell’evento Step della porta controlliamo se il numero di diamanti è 0 e se è vero si distrugge.
C’è un’azione per questo.

Step

Emetteremo anche un suono in modo che il giocatore senta che la porta si è aperta.

 

Miglioramenti grafici

Adesso che le basi del gioco sono in campo rendiamolo un po’ più carino.

I muri sono piuttosto ripetitivi.
Realizziamo 3 tipi diversi di oggetto muro, uno per gli angoli, uno per i muri verticali e un altro per i muri orizzontali.

Dagli ad ognuno la sprite corretta e rendili SolidWall Corner Wall Horizontal Wall Vertical
Adesso risistemando un po’ i livelli, appariranno più belli.

BackgroundAnche aggiungere un’immagine di sfondo aiuta.

Per evitare di dover specificare gli eventi di collisione della persona con tutti questi muri diversi (e più avanti lo stesso con i mostri) utilizziamo un’importante tecnica presente in GameMaker.
Rendiamo l’oggetto muro d’angolo parentgenitore, degli altri oggetti muro.
Questo significa che gli oggetti muro si comporteranno come varianti dell’oggetto muro d’angolo.
Avranno esattamente lo stesso comportamento (a meno che non specifichiamo per essi diversi comportamenti).
Anche per altre istanze sarà la stessa cosa.
Quindi dobbiamo specificare le collisioni con l’angolo.
Quest’azione sarà utilizzata automaticamente per tutti gli altri oggetti muro.
Anche all’oggetto porta possiamo dare il muro d’angolo come parent.

Il punteggio

Diamo al giocatore un punteggio in modo che possa misurare i suoi progressi.
È piuttosto semplice.
Per ogni diamante raccolto gli assegniamo 5 punti.
Quindi nell’evento Destroy del diamante aggiungiamo 5 a score.
Completare un livello regala 40 punti quindi aggiungiamo 40 a score nell’evento di collisione della meta con il personaggio.

Quando il giocatore completa l’ultimo livello deve essere visualizzata la classifica dei punteggi migliori.
Questo è semplice in GameMaker perché esiste un’azione appropriata.
L’oggetto meta diventa quindi un po’ più complicato.

Quando si scontra con il personaggio viene eseguito il seguente evento:

obj_goal

Aggiunge qualcosa al punteggio, emette un suono, aspetta per un po’ e quindi passa al prossimo livello oppure, se questo è l’ultimo livello, visualizza un messaggio , la classifica e fa ripartire il gioco.

Osserva che il punteggio appare automaticamente nel titolo della finestra.
Questo è leggermente brutto.
Per questo creeremo un oggetto di controllo.
Non ha bisogno di una sprite.
Sarà posizionato su tutti i livelli.
Esegue alcuni controlli globali su quello che sta succedendo.
Per il momento lo utilizziamo soltanto per visualizzare il punteggio.
Nel suo evento Draw utilizziamo Set Font e Set Color e poi Draw the score.

Schermata iniziale

La prima schermata del gioco dovrebbe mostrare il nome del gioco, il nome dell’autore, ….
Per questo utilizziamo il primo livello.
Creiamo una risorsa background con un’immagine piacevole.
Questo sfondo è utilizzato per il primo livello (è meglio se disabiliti il colore di sfondo e la tassellatura).
L’oggetto start_controller (invisibile, naturalmente) semplicemente aspetta finché l’utente non preme un tasto e poi passa al prossimo livello.
Il controllare inoltre imposta score a 0 e si assicura che il punteggio non venga visualizzato nella barra del titolo della finestra.

Suoni

Un gioco senza suoni è piuttosto noioso.
Quindi ci servono dei suoni.
Prima di tutto ci serve un suono di sottofondo.
Per questo utilizziamo qualche file midi piacevole.
Facciamo partire il pezzo nell’oggetto start_controller impostando loop a true.
Poi ci servono degli effetti audio per la raccolta di un diamante, la porta che si apre, e per il raggiungimento della meta.
Quando si raggiunge la meta, e dopo l’emissione del suono, è bene introdurre un’azione Sleep per avere una breve attesa prima di passare al livello successivo.

Nuovi livelli

Adesso possiamo realizzare dei livelli con diamanti.
Osserva che il primo livello senza diamanti possiamo semplicemente lasciarlo.
Questo va bene perché introduce il giocatore al concetto di movimento verso la bandiera a scacchi prima che abbia a che fare con la raccolta dei diamanti.
Se diamo nomi significativi ai livelli (Caption for the room nella scheda Settings del livello) il giocatore capirà cosa fare.

 

Mostri e altre sfide

Al punto in cui siamo adesso, il gioco sembra carino ma è completamente banale, e quindi noioso da giocare.
Abbiamo bisogno di un po’ d’azione sotto forma di mostri.
Inoltre aggiungeremo delle bombe, dei blocchi mobili e delle buche.

I mostri

Realizzeremo 3 tipi diversi di mostri:

  1. uno che si muove a destra e a sinistra, orizzontalmente
  2. uno che si muove in alto e in basso, verticalmente
  3. e uno che si muove nelle 4 direzioni.

Aggiungere un mostro è molto semplice.
Si tratta di un oggetto che comincia a muoversi e cambia direzione quando colpisce il muro.
Quando il personaggio tocca un mostro viene ucciso, cioè il livello riparte e il giocatore perde una vita.
Il giocatore riceve alla partenza 3 vite.

Monster 1Realizziamo il primo mostro che si muove a destra e a sinistra.
Utilizziamo una semplice sprite e poi creiamo l’oggetto corrispondente.
Nel suo evento Create decide se andare a destra o a sinistra.
Inoltre, per rendere la vita più difficile, impostiamo speed a un valore piuttosto alto.
Quando avviene una collisione cambia la sua direzione orizzontale.

Monster 2Il secondo mostro si comporta esattamente come il primo eccetto per la direzione iniziale che sarà verso l’alto oppure verso il basso e quando sbatte col muro inverte la direzione verticale.

Monster 3Il terzo mostro è leggermente più complesso.

Inizia muovendosi orizzontalmente o verticalmente.
Quando sbatte col muro prova a girarsi a sinistra oppure a destra.
Se non è possibile torna indietro.

monster_all
Per evitare problemi con i mostri che hanno immagini leggermente più piccole deselezioniamo Precise collision checking e impostiamo Bounding box alla maschera Full image.

Quando il personaggio tocca un mostro dobbiamo far emettere un suono, aspettare per un po’, decrementare di 1 il numero di vite e poi far ripartire il livello.
Osserva che l’ordine è cruciale: una volta che riparte il livello, le altre azioni non vengono più eseguite.
L’oggetto controllore, nell’evento No more lives, visualizza la classifica e fa ripartire il gioco.

Le vite

Abbiamo utilizzato il meccanismo di GameMaker per dare 3 vite al giocatore.
Sarebbe carino se mostrassimo anche il numero di vite.
L’oggetto controllore potrebbe farlo utilizzando la stessa modalità del punteggio.

Live

Ma è più carino se si vedono delle piccole immagini del personaggio per le vite.
C’è un’azione apposita nella scheda score.

L’evento Draw apparirà così:

controller_main

Osserva che abbiamo usato anche una risorsa di tipo Font per visualizzare il punteggio.

Le bombe

Aggiungiamo le bombe e i detonatori per farle esplodere.
L’idea è che quando il personaggio si avvicina al detonatore tutte le bombe esplodono, distruggendo tutte le cose nelle loro vicinanze.
Questo può servire per creare buchi nei muri e per distruggere i mostri.
Sono necessari 3 oggetti: un detonatore, una bomba e un’esplosione.
Per ciascuno è necessaria una sprite appropriata.

bombLa bomba è semplicissima.
Sta lì e non fa nulla.
Per essere sicuri che i mostri ci passino sopra (piuttosto che sotto) impostiamo depth a 10.
Le istanze degli oggetti sono disegnate in ordine di profondità, depth.
Quelle col valore più alto sono disegnate per prime.
E quindi finiranno dietro le istanze con valori più bassi.
Impostando depth a 10 per la bomba gli altri oggetti, che hanno depth a 0 di default, saranno disegnati sopra di essa.

TriggerAnche il detonatore è piuttosto semplice.

Quando collide con il personaggio trasforma tutte le bombe in esplosioni.
Questo si ottiene utilizzando l’azione che cambia un oggetto in un altro.
In cima indichiamo che si deve applicare a tutte le bombe.

Change Instance

ExplosionL’oggetto esplosione visualizza proprio l’animazione dell’esplosione.
Dopo l’animazione si distrugge.
Devi assicurarti che l’origine dell’esplosione sia nel posto giusto quando la bomba si trasforma in esplosione.
L’oggetto deve distruggere tutto quello che tocca.

Questo richiede un po’ di lavoro.

  • Non vogliamo che l’esplosione si autodistrugga quindi la spostiamo fuori temporaneamente.
  • Utilizziamo le azioni per distruggere tutte le istanze alle posizioni intorno alla posizione originaria dell’esplosione.
  • Infine rimettiamo l’esplosione al posto originario.

obj_explosion

Osserva che va tutto storto se il personaggio è vicino a una bomba!
Assicurati che i detonatori non siano vicini alle bombe.
Bisogna progettare con cura i livelli con bombe e detonatori in modo che presentino sfide interessanti.

Blocchi e buche

Realizziamo qualcos’altro per rendere il gioco più complicato.
Realizziamo dei blocchi che possono essere spinti dal giocatore.
Inoltre realizziamo delle buche che il giocatore non può attraversare ma che possono essere colmate con i blocchi per creare nuovi passaggi.
Così si presentano nuove possibilità per il gioco.
I blocchi devono essere spinti in modo particolare per creare i passaggi.
E puoi utilizzare i blocchi per catturare i mostri.

BlockIl blocco è un oggetto solido.
La cosa importante è che deve seguire il movimento del personaggio quando viene spinto.
Quando collide con il personaggio svolgiamo le seguenti azioni:

  • Controlliamo se la posizione relativa (8*other.hspeed8*other.vspeed) è vuota.
    Questa è la posizione dove deve essere spinto il blocco.
  • Se è vuota spostiamo lì il blocco.

Facciamo la stessa cosa se alla posizione c’è una buca.
Per evitare che i mostri corrano sui blocchi rendiamo il muro d’angolo parent del blocco.
C’è ancora un piccolo problema.
Siccome l’evento di collisione è definito tra il personaggio e il muro d’angolo e non tra il personaggio e il blocco, l’evento viene eseguito e il personaggio viene fermato.
Non è quello che vogliamo.
Per risolverlo aggiungiamo un’azione inattiva (un commento) nell’evento collisione della persona con il blocco.
Adesso l’evento viene eseguito comunque, e non ferma il personaggio.
Per essere precisi, il nuovo evento collisione sovrascrive l’evento collisione del parent.
Come detto prima, puoi fare in questo modo per dare a un oggetto figlio un comportamento leggermente diverso dal suo oggetto genitore.

HoleLa buca è un oggetto solido.
Quando collide con il blocco distrugge se stessa e il blocco.
Inoltre impostiamo come suo parent il muro d’angolo in modo che si comporti come un muro.

Con i blocchi e le buche puoi creare molti livelli intriganti.
Tuttavia, c’è un piccolo problema.
Puoi rimanere facilmente bloccato e quindi il livello diventa insolubile.
Allora dobbiamo dare al giocatore la possibilità di ricominciare il livello, al costo di una vita.
Per questo utilizziamo il tasto R, per ripartire.
In questo evento Keyboard del controllore semplicemente sottraiamo 1 dalle vite e facciamo ripartire il livello.

Con questo è finita la nostra terza versione del gioco di labirinto.
Adesso ha tutti gli ingredienti per realizzare tanti livelli interessanti.

 

Miglioramenti finali

Finiamo definitivamente il gioco.
Dobbiamo migliorare ancora la grafica.
Inoltre abbiamo bisogno di un certo numero di livelli più interessanti.
Per questo aggiungiamo alcuni bonus e altre caratteristiche.

Miglioramenti grafici

L’attuale grafica del gioco è piuttosto povera.
Facciamo allora qualcosa per migliorarla.
La cosa che maggiormente vogliamo cambiare è che il personaggio guardi nella direzione in cui si muove.
Person NiceIl modo più semplice per ottenere questo è utilizzare una nuova sprite che consiste di 4 sottoimmagini, una per ogni direzione:

Normalmente GameMaker cicla tra queste sottoimmagini.
Possiamo evitarlo impostando a 0 la variabile image_speed.

Change SpriteQuando cambiamo la direzione del personaggio, possiamo cambiare anche la sottoimmagine visualizzata dall’azione che cambia la sprite:

Una cosa simile possiamo farla per tutti i mostri ma non hanno un evento esplicito dove cambiano direzione.
È più semplice aggiungere un controllo alla fine del passo, con l’evento End step, per vedere in quale direzione il mostro si sta muovendo e adattare la sprite di conseguenza.

Bonus

Aggiungiamo due bonus:

  • 100 punti: Bonus 1
  • 1 vita: Bonus 2

Sono estremamente semplici: quando vengono toccati dal personaggio emettono un suono, si distruggono e aggiungono dei punti al punteggio oppure 1 al numero di vite.
Questo è tutto.

Sensi unici

Per rendere i livelli più complicati aggiungiamo delle strade a senso unico., cioè che possono essere attraversate in un’unica direzione.
Per questo realizziamo 4 oggetti, uno per ogni direzione, ciascuno con la forma di una freccia che punta nella direzione del movimento: Move Up Move Right Move Down Move Left.
Quando il personaggio è completamente su di essa ci dobbiamo muovere nella giusta direzione.
Lo facciamo nell’evento Step del personaggio.
Controlliamo se il personaggio è allineato alla griglia nel modo giusto e se si trova sulla freccia particolare.
Se corrisponde impostiamo il movimento nella direzione giusta.
Impostiamo speed a 8 per renderlo più evidente.

Mostri impauriti

Per realizzare livelli che assomiglino a quelli di Pacman diamo ai mostri una variabile di nome afraid.
Nell’evento Create la impostiamo a 0 (false).

Mostro 3Quando il personaggio incontra un nuovo oggetto anello impostiamo la variabile di tutti i mostri a true e cambiamo la sprite per far vedere che il mostro è piuttosto impaurito.
Adesso quando il personaggio incontra il mostro prima controlliamo se è impaurito o meno.
Se il mostro è impaurito viene spostato alla sua posizione iniziale.
Altrimenti, il giocatore perde una vita.
Guarda il gioco per i particolari.

Completiamo il gioco

Abbiamo creato un sacco di oggetti ma ancora non abbiamo un vero gioco.
Una caratteristica vincente nei giochi è il progetto dei livelli.
Dovrebbero andare dal più facile al più difficile.
All’inizio ci dovrebbero essere pochi oggetti e più avanti dovrebbero apparire gli altri.
Assicurati di proporre delle sorprese che spuntano fuori soltanto intorno al livello 50 e così via.
Chiaramente i livelli dovrebbero essere adattati ai giocatori attesi.
I rompicapi per bambini sono completamente diversi da quelli per adulti.

Inoltre un gioco ha bisogno di una documentazione.
In GameMaker puoi aggiungere facilmente una documentazione utilizzando Game Information.

Infine, i giocatori non vogliono giocare l’intero gioco in una sola volta.
Allora devi aggiungere un meccanismo per caricare e salvare i giochi.
Fortunatamente, è molto semplice.
In GameMaker è presente un meccanismo di load/save:

F5 salva il gioco corrente
F6 carica l’ultimo gioco salvato.

Dovresti scriverlo nella documentazione…

Considera il demo di questo tutorial: aprilo, giocaci, controllalo e cambia tutto quello che vuoi.
In particolare, dovresti aggiungere molti più livelli (al momento sono solo 20).
Inoltre potresti aggiungere altri oggetti, come

  • chiavi che aprono certe porte,
  • transporter che ti spostano da un posto all’altro nel labirinto,
  • proiettili che il personaggio spara contro i mostri,
  • porte che si aprono e si chiudono in certi momenti,
  • ghiaccio sul quale il personaggio scivola in una certa direzione,
  • trappole …

 

Conclusioni

Spero che questo tutorial ti abbia aiutato nella creazione dei tuoi giochi con GameMaker.
Ricordati di progettare prima il tuo gioco e poi di realizzarlo passo dopo passo (o meglio oggetto dopo oggetto).
Ci sono sempre molte strade diverse con le quali si possono raggiungere le cose.
Quindi se qualcosa non funziona prova in qualche altro modo.
Buona fortuna!