Crea un gioco Match-3 in Costruisci 2 Movimento a blocchi

Nella parte precedente di questa serie abbiamo apportato alcune piccole ma importanti modifiche a molti dei sistemi che abbiamo creato per il nostro gioco Match-3. Con questi miglioramenti implementati, stiamo tornando in pista e implementiamo uno degli ultimi due principali sistemi per il gioco: il sistema di Movimento a blocchi.

Questo tutorial ti guiderà attraverso l'intero sviluppo del sistema che consentirà ai blocchi di salire in cima allo schermo e coprirà anche la creazione di tutti i sistemi più piccoli che avremo bisogno di implementare per supportare il sistema di movimento. Mentre gli argomenti trattati in questo tutorial non sono troppo complessi, c'è molto da approfondire, quindi proviamoci.


Demo del gioco finale

Ecco una demo del gioco a cui stiamo lavorando in questa serie:




1. Spostamento dei blocchi

Prima di iniziare a spostare i blocchi, dobbiamo apportare una piccola modifica agli eventi che generano i Blocchi. Vai al Sistema> All'inizio del layout evento e cambiare la Y per loop da cui partire 0 a 3, invece di da 0 a 7 come all'inizio.

L'evento dovrebbe ora assomigliare a questo:


Il motivo per cui abbiamo apportato questa modifica è perché vogliamo che il gioco inizi con meno blocchi sullo schermo, in modo che non finisca più rapidamente quando aggiungiamo un Game Over nel prossimo tutorial.

Successivamente, creeremo una variabile che rappresenterà la velocità dei blocchi:

Variabile globale: Nome = CurrentSpeed ​​Type = Number Value = 0.2

Ora creeremo l'evento che sposta effettivamente i blocchi:

Evento: Condizione: Sistema> Ogni X Secondi Intervallo (secondi) = Velocità attuale Azione: Blocco> Sposta ad angolo = = 90 Distanza = 1

L'evento dovrebbe assomigliare a questo:


Se esegui il gioco dopo aver aggiunto questo evento, la prima cosa che dovresti vedere è che i blocchi cadono, a causa della gravità che abbiamo implementato in un precedente tutorial. Dopodiché, i blocchi dovrebbero salire lentamente fino a quando non si trovano nella loro posizione originale, quindi rilasciarli di nuovo. Questo si ripeterà all'infinito fintanto che non farai nulla per i Blocchi.

Questo accade perché i Blocchi si stanno spostando oltre il punto in cui si suppone che la gravità abbia inizio, e stanno scoprendo che non ci sono blocchi sotto di loro, facendoli cadere tutti. Mentre questo è un problema, non è il primo che voglio guardare.


2. Riparare lo scambio

Esegui il gioco e prova a fare uno scambio di qualsiasi tipo. Quando lo fai, dovresti vedere che i blocchi iniziano a rimanere bloccati uno dietro l'altro, rimanendo bloccati in posizioni non allineate con la griglia, e generalmente in modo anomalo. Ci sono due ragioni per questo problema.

Il primo problema è che, anche se stiamo spostando i Blocchi stessi, non stiamo spostando il LeftBlock, RightBlock, Topblock, e BottomBlock oggetti con essi, il che significa che i blocchi che usi per rilevare gli swap non si muovono con la griglia dei blocchi - sono semplicemente seduti nella posizione in cui sono impostati quando si prende in mano un blocco.

Quindi, quando provi a fare uno scambio, i blocchi vengono messi fuori posto perché i blocchi di rilevamento dello swap non sono stati adattati alla griglia. (Questo è anche il motivo del secondo problema che stiamo avendo, ovvero che non stiamo modificando le posizioni che abbiamo archiviato nel BlockPositions array.)

La GIF di seguito illustra questo problema:


Come puoi vedere nella GIF, i blocchi di rilevamento dello swap non si muovono, anche se i blocchi stessi sono.

Per risolvere entrambi questi problemi, aggiungeremo altre azioni all'evento appena creato:

Azione: BottomBlock> Move with Angle Angle = -90 Distance = 1 Action: LeftBlock> Move with Angle Angle = -90 Distance = 1 Action: RightBlock> Move with Angle Angle = -90 Distance = 1 Action: TopBlock> Sposta con angolo = -90 Distanza = 1 Azione: BlockPositions> Imposta a XY X = 0 Y = 1 Valore = BlockPositions.At (0,1) - 1 Azione: BlockPositions> Imposta a XY X = 1 Y = 1 Valore = BlockPositions.At ( 1,1) - 1

L'evento dovrebbe ora assomigliare a questo:


Le prime quattro azioni che abbiamo appena aggiunto regolano le posizioni del LeftBlock, Topblock, RightBlock, e BottomBlock oggetti in modo che rimangano allineati con la griglia del blocco. I secondi due eventi regolano i valori Y che abbiamo memorizzato nel BlockPositions array in modo che rimangano in linea con la griglia dei blocchi.

Se testate di nuovo il gioco a questo punto, lo swap dovrebbe essere in gran parte risolto.

A questo punto, c'è ancora un altro problema che dobbiamo affrontare per fare in modo che lo scambio funzioni correttamente. Esegui il gioco e prova a fare uno scambio verso il basso con uno qualsiasi dei blocchi nella riga in basso mentre quella riga è parzialmente sotto l'area inferiore del campo di gioco:

Fai lo scambio mentre i blocchi si trovano dietro il bordo, come quelli evidenziati nell'immagine sopra.

Se l'hai fatto correttamente, dovresti vedere che non è successo nulla e che i blocchi non si sono invertiti. Se hai aspettato troppo a lungo, i blocchi potrebbero essersi scambiati perché si erano spostati di nuovo sopra il bordo del campo di gioco, quindi se ciò accadesse riprovare quando cadono e dovresti vedere questo problema verificarsi.

Questo problema è piuttosto semplice da risolvere e da comprendere. Se si guarda il codice degli swap verso il basso, si dovrebbe trovare l'evento che abbiamo aggiunto nel tutorial precedente che impedisce al giocatore di effettuare swap discendenti che causano la caduta del blocco dalla parte inferiore del campo di gioco. Dal momento che questa affermazione impedisce al giocatore di effettuare swap discendenti quando il BottomBlock l'oggetto è inferiore alla posizione iniziale Y del blocco, impedisce che i blocchi vengano scambiati una volta caduti e consente di effettuare nuovamente lo scambio una volta che hanno spostato nuovamente la loro posizione originale.

Per correggere questa affermazione faremo una piccola modifica alla condizione:

Condizione: BottomBlock> Confronta confronto Y = minore o uguale coordinata Y = SPAWNY + ((Block.Width + 2) / 2)

La condizione dovrebbe ora apparire come questa:


Questa modifica significa che uno scambio verso il basso può avvenire solo mentre il BottomBlock l'oggetto è al massimo un mezzo blocco sotto la posizione Y in cui i blocchi iniziano. Ciò significa anche che, una volta che avremo generato nuove file di blocchi e li avremo spostati sullo schermo dal basso, questi blocchi potranno essere scambiati solo in questo modo una volta almeno la metà del blocco è visibile.

Metteremo anche una restrizione simile in tutti i nostri eventi di scambio per garantire che tutti diventino utilizzabili allo stesso tempo e che un blocco non possa essere scambiato affatto fino a quando almeno la metà di esso sia visibile. Ancora una volta, questo aiuterà anche quando integreremo il sistema che genera nuove file di blocchi. Per fare ciò, aggiungeremo una nuova condizione a ciascuno dei rimanenti tre eventi di scambio.

Le condizioni che aggiungiamo saranno esattamente le stesse di quelle che abbiamo appena modificato BottomBlock evento, tranne che faranno riferimento al Topblock, RightBlock, e LeftBlock oggetti invece del BottomBlock oggetto, a seconda dell'evento in cui si trova.

La nuova condizione per il Topblock L'evento dovrebbe essere:

Condizione: TopBlock> Confronta confronto Y = minore o uguale coordinata Y = SPAWNY + ((Block.Width + 2) / 2)

La nuova condizione per il LeftBlock L'evento dovrebbe essere:

Condizione: LeftBlock> Confronta confronto Y = minore o uguale coordinata Y = SPAWNY + ((Block.Width + 2) / 2)

La nuova condizione per il RightBlock L'evento dovrebbe essere:

Condizione: RightBlock> Confronta confronto Y = minore o uguale coordinata Y = SPAWNY + ((Block.Width + 2) / 2)

Tutto il tuo Alla caduta di DragDrop L'evento dovrebbe ora assomigliare a questo:


Con queste nuove condizioni, abbiamo risolto i nostri meccanismi di scambio e abbiamo iniziato a preparare i sistemi esistenti per il prossimo sistema che stiamo aggiungendo: quello che genererà nuove file di blocchi.


3. Generare più blocchi

Ora che abbiamo i blocchi che si muovono a una velocità costante, dobbiamo rendere le nuove file di blocchi spawn nel momento giusto e permettere al giocatore di continuare a giocare per tutto il tempo che vogliono. Useremo una funzione per generare le nuove file di blocchi e useremo un evento che rileva quando i blocchi sono in linea con Spawny per attivare quella funzione.

Quindi, per prima cosa, facciamo la funzione stessa.

Evento: Condizione: Funzione> On function Nome = "SpawnNewBlocks" Condizione: Sistema> Nome = "X" Inizio indice = 0 Fine indice = 7 Azione: Sistema> Crea oggetto Oggetto = Livello blocco = 1 X = SPAWNX + (loopIndex ( "X")) * (Block.Width + 2) Y = SPAWNY + (Block.Width + 2) Azione: Blocco> Imposta valore Istanza Variabile = Colore Valore = piano (Random (1,7)) Azione: Sistema> Aggiungi alla variabile = NumBlocks Valore = 1

Il tuo nuovo evento dovrebbe assomigliare a questo:


Se utilizzata, questa funzione crea una fila di blocchi sotto la riga inferiore di blocchi nel campo di gioco. Allo stato attuale, però, in realtà non usiamo questa funzione in alcun modo, quindi facciamo in modo che l'Evento faccia ciò:

Evento: Condizione: Sistema> Ogni X secondi Intervallo (secondi) = CurrentSpeed ​​Condizione: Blocco> Confronta Y Confronto = Uguale a Y = SPAWNY Condizione: Inverti: Blocco> Sta trascinando Azione: Funzione> Funzione chiamata Nome = "SpawnNewBlocks"

Il tuo nuovo evento dovrebbe assomigliare a questo:


L'evento appena creato controlla la posizione Y dei blocchi ogni volta che vengono spostati. Se trova eventuali blocchi in linea con Spawny, innesca il SpawnNewBlocks () funzione come abbiamo discusso in precedenza. Controlla inoltre che il blocco trovato non sia quello che viene trascinato dal giocatore.

Se testerai il tuo gioco a questo punto, funzionerà, ma dovresti notare uno strano problema. Nel momento in cui inizi il gioco, i tuoi blocchi cadranno come se non ci fossero blocchi sotto di loro, ma dopo quel punto tutto funziona perfettamente, e nuovi blocchi vengono generati ogni volta che sono necessari.

Questo accade perché, quando il gioco inizia, elabora il codice di gravità prima il codice che genera nuove file di blocchi. Per risolvere questo problema, apporteremo una piccola modifica al codice che genera il gruppo iniziale di blocchi in modo che vengano generati sotto il punto in cui sarebbe necessaria una nuova riga. Ciò gli consente di evitare l'esecuzione immediata del codice gravità e di creare la nuova riga di blocchi una volta che i blocchi esistenti si trovano nella posizione corretta.

Vai all'Evento che genera il gruppo iniziale di blocchi e modifica l'Azione che effettivamente crea il blocco. Cambia l'azione in questo modo:

Azione: Sistema> Crea oggetto Object = Block Layer = 1 X = SPAWNX + (loopIndex ("X")) * (Block.Width + 2) Y = SPAWNY - (loopIndex ("Y")) * (Block.Width + 2) + 5

L'evento dovrebbe ora assomigliare a questo:


Questa modifica significa che i blocchi genereranno cinque pixel sotto Spawny. Ciò significa che i blocchi dovranno effettivamente salire di cinque volte prima che una nuova riga venga generata, e risolve il nostro problema.


4. Un po 'di animazione

A questo punto i nostri blocchi si stanno muovendo e abbiamo creato nuove righe. Inoltre, ricorda che in precedenza abbiamo impedito al giocatore di utilizzare qualsiasi blocco finché almeno la metà del blocco è visibile. Mentre questa è una buona caratteristica, il giocatore potrebbe non capire perché un blocco non può essere usato immediatamente quando diventa visibile, anche se non è visibile gran parte di esso al momento.

A causa di questo potenziale problema di interfaccia utente, faremo in modo che ogni blocco utilizzi lo sprite di blocco grigio (all'inizio dei frame di animazione del blocco) quando si trova in questo stato inutilizzabile. Questo renderà chiaro al giocatore quando un blocco diventa utilizzabile e ci darà la possibilità di usare finalmente la nostra ultima immagine del blocco.

Puoi vedere un esempio di come apparirà quando i blocchi passeranno da inattivo a attivo nella GIF di seguito:


L'Evento che creiamo includerà anche una seconda Condizione che controlla per assicurarsi che il blocco che sta guardando non venga trascinato. Questa Condizione ci permette di assicurare che quando il giocatore trascina un blocco sotto il punto in cui i blocchi diventano utilizzabili, non cambierà la sua immagine in modo che sia grigio, e rimarrà il colore che dovrebbe essere.

Per far funzionare questa animazione, dobbiamo prima aggiungere un nuovo evento:

Evento: Condizione: Blocco> Confronto Confronto Y = Maggiore di Y = SPAWNY + ((Block.Width + 2) / 2) Condizione: Inverti: Blocca> Sta trascinando Azione: Blocca> Imposta frame Numero frame = 0

Il nuovo evento dovrebbe assomigliare a questo:


Ora dovresti essere in grado di testare il tuo gioco e dovresti vedere che i blocchi stanno usando l'immagine grigia quando sono sotto il punto in cui diventano utilizzabili.


5. Abilitare e disabilitare il trascinamento / rilascio

Se esegui il gioco ora, noterai che anche se i blocchi non possono essere scambiati l'uno con l'altro quando sono grigi, i blocchi grigi possono ancora essere trascinati e manipolati. Questo perché non abbiamo mai disabilitato le funzionalità Drag / Drop del blocco quando abbiamo impedito al giocatore di scambiare con loro.

Per evitare che i blocchi grigi possano essere spostati, modificheremo l'evento che abbiamo creato nella sezione precedente. Per prima cosa aggiungeremo una nuova azione che disattiva il trascinamento quando il blocco si trova sotto il punto in cui diventa utilizzabile.

Aggiungi questa azione all'evento che abbiamo creato in precedenza:

Azione: Blocca (DragDrop)> Imposta stato abilitato = Disabilitato

Stiamo anche aggiungendo un'istruzione Else per questo evento che consente di trascinare il blocco nuovamente una volta che è sopra il punto in cui il blocco diventa utilizzabile:

Evento: Condizione: Altrimenti Azione: Blocca (DragDrop)> Imposta stato abilitato = Abilitato

Con entrambe queste modifiche, l'evento dovrebbe assomigliare a questo:


Se testate il gioco a questo punto, i blocchi non dovrebbero più essere utilizzabili quando sono grigi e dovrebbero funzionare nello stesso modo in cui hanno sempre quando non sono.


6. Cambiamenti di velocità

L'ultima cosa che voglio trattare in questo articolo è il sistema che ci permetterà di cambiare la velocità del gioco nel tempo. In particolare, questo è il sistema che farà muovere i blocchi più velocemente mentre il giocatore ne elimina più.

Il sistema che stiamo per creare è relativamente semplice: ogni volta che il giocatore ottiene un certo numero di punti, la velocità del gioco aumenterà in base a un modificatore che creeremo e al numero di punti che il giocatore deve ottenere il prossimo aumento di velocità cambierà in base a un secondo modificatore.

Prima di poter effettivamente iniziare a creare gli eventi per questo sistema, creeremo un paio di variabili globali per gestire le nuove funzionalità per noi:

Variabile globale: SPEEDMOD Tipo = Numero Valore iniziale = 0.8 Costante = Sì Variabile globale: PointsForSpeedUp Tipo = Numero Valore iniziale = 400 Costante = Nessuna variabile globale: PointsBetweenSpeedUps Tipo = Numero Valore iniziale = 400 Costante = Nessuna variabile globale: POINTSFORSPEEDUPMOD Tipo = Numero Iniziale valore = 1,4 Costante = Sì

Le tue nuove variabili dovrebbero assomigliare a questo:


Ora che abbiamo le variabili, spiegherò cosa fa ciascuna.

  • SPEEDMOD è la variabile moltiplicheremo la velocità per modificarla ogni volta che il giocatore raggiunge il numero di punti di cui ha bisogno per causare un aumento di velocità.
  • PointsForSpeedUp è il numero di punti che il giocatore deve colpire alla prossima velocità.
  • PointsBetweenSpeedUps rappresenta quanto PointsForSpeedUp la variabile aumenta quando il giocatore aumenta la velocità, per regolarlo in modo che la successiva accelerazione richieda ancora più punti. In questo momento è 400, come PointsForSpeedUp, ma quando il giocatore ottiene effettivamente una velocità sarà moltiplicato per POINTSFORSPEEDUPMOD prima che venga aggiunto a PointsForSpeedUp.
  • Finalmente, POINTSFORSPEEDUPMOD è la variabile che useremo per modificare il numero di punti di cui il giocatore ha bisogno per arrivare ad aumentare la propria velocità un'altra volta oltre quello che ha ottenuto più recentemente.

Insieme all'impostazione delle variabili, dobbiamo anche creare un nuovo oggetto sprite che fungerà da avviso per il giocatore quando la velocità aumenta.

Vai a Layout 1 e segui questi passaggi per creare il nuovo sprite:

  1. Inserisci un nuovo folletto oggetto su Layout 1.
  2. Con l'Animation Editor, apri l'immagine SpeedIncImage.png.
    1. Impostare il Nome a SpeedIncreaseIndicator.
    2. Impostare il Strato a Campo di gioco.
    3. Impostare il Posizione a 188, 329.
    4. Impostato Visibilità iniziale a Invisibile.
      1. Aggiungere un dissolvenza Comportamento allo Sprite.
      2. Impostato Attivo all'avvio a No.
      3. Impostare il Tempo di dissolvenza a 2.5.
      4. Impostato Distruggere a No.

Il tuo layout dovrebbe ora assomigliare a questo:


Ora creeremo effettivamente l'evento che cambia la velocità:

Evento: Condizione: Funzione> On function Nome = "CheckForSpeedUp" Condizione: Sistema> Confronta variabile Variabile = Confronto punteggio = Maggiore o uguale Valore = PuntiForSpeedUp Azione: SpeedIncreaseIndicator> Imposta visibilità Visibilità = Visibile Azione: SpeedIncreaseIndicator> Avvia dissolvenza Sistema di azione> Imposta valore Variabile = CurrentSpeed ​​Value = CurrentSpeed ​​* SPEEDMOD Sistema di azione> Imposta valore Variabile = PuntiBetweenSpeedUp Valore = PuntiBetweenSpeedUp * POINTSFORSPEEDUPMOD Azione: Sistema> Aggiungi a variabile = PuntiForSpeedUp Valore = PuntiBetweenSpeedUp

Il tuo evento dovrebbe assomigliare a questo:


Quando viene chiamata questa funzione, controlla se il giocatore ha segnato abbastanza punti da giustificare un aumento di velocità. Se hanno, allora:

  • attiva lo sprite che dice al giocatore che la velocità è aumentata rendendola visibile e avviando la dissolvenza
  • aumenta la velocità moltiplicandola per il modificatore
  • determina il numero di punti necessari prima della prossima accelerazione, e
  • aggiunge quel valore al numero totale di punti che il giocatore dovrà avere prima che la velocità aumenti di nuovo.

Con questa funzione completa, dobbiamo solo assicurarci che venga chiamata. Vai al GivePoints () funzione e aggiungi questa azione alla fine dell'evento principale e dell'evento secondario:

Azione: Funzione> Funzione chiamata Nome = "CheckForSpeedUp"

Il GivePoints () la funzione dovrebbe ora assomigliare a questa:


Con questo evento completo dovresti essere in grado di testare il tuo gioco e vedere il sistema di accelerazione in azione.

Mancia: Mentre giocavo di più, ho scoperto che questi valori si sentivano un po 'off, quindi ti suggerisco di prendere un po' di tempo per sperimentare con il sistema, e trovare i valori che ti senti più a tuo agio con.


Conclusione

In questo articolo abbiamo trattato molti argomenti diversi, ma tutto ciò di cui ci siamo occupati era direttamente o indirettamente correlato al modo in cui il sistema di movimento funzionava come volevamo. Mentre ci è voluto del tempo e ci ha richiesto di realizzare più sistemi di quelli che avremmo potuto prevedere all'inizio, ne è valsa la pena e alla fine abbiamo trovato un sistema molto forte.

Per quanto ne abbiamo già parlato, penso che questo sia un buon posto per concludere questo articolo. Il prossimo articolo dovrebbe essere il tutorial finale di questa serie e tratteremo molti argomenti minori all'interno di esso, ma la cosa più importante che stiamo affrontando è sicuramente l'eliminazione delle partite pre-fatte.

Se vuoi iniziare a cercare di capire come eliminarli, dai un'occhiata a come rileviamo le partite per cominciare. Il sistema che creeremo sarà molto simile a quel sistema, tranne che userà le corrispondenze che trova in un modo diverso. Comincia a pensarci e guarda cosa riesci a trovare, e ti vedrò di nuovo qui la prossima volta per l'ultimo importante tutorial della serie.