Crea un gioco Match-3 in Construct 2 Match Detection

Finora, questa serie ha coperto le basi della creazione di un gioco Match-3 e implementando gli elementi di gameplay iniziali come lo scambio di blocchi. In questo tutorial, svilupperemo tutto ciò e inizieremo a rilevare quando il giocatore ha fatto una partita.


Demo del gioco finale

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




1. Rilevare una partita

Per ora, implementeremo solo una versione di base del sistema di matching, concentrandoci sul trovare quando esistono corrispondenze e distruggere blocchi abbinati. Negli articoli successivi continueremo a sviluppare e far progredire il sistema.

Mancia: Dovresti leggere come funziona una funzione ricorsiva, se non lo sai già; essenzialmente, è una funzione che chiama se stessa. Le funzioni ricorsive possono funzionare in modo simile ai cicli, ma dato che possono anche contenere e restituire variabili, hanno molti più usi di quanto non facciano i loop.

Come per il tutorial precedente, desidero innanzitutto discutere di come funzionerà il sistema e quindi tentare di costruirlo.

  • Il sistema di corrispondenza scorrerà tra tutte le istanze di Bloccare oggetto.
  • Per ciascuno Bloccare, passerà il colore e la posizione del blocco che sta osservando in una funzione ricorsiva, che guarderà al vicino orizzontale o verticale e determinerà se sono dello stesso colore.
  • Se viene trovata una corrispondenza, chiamerà di nuovo la funzione con la posizione e il colore del nuovo blocco, anziché quella originale.
  • Questo continuerà fino a quando non trova alcuna corrispondenza. A quel punto, controllerà quante partite ha trovato.
  • Se trova tre o più incontri, segna tutti i blocchi che ha appena visto Matched con il IsMatched variabile di istanza creata in uno dei tutorial precedenti; altrimenti, non fa nulla.
  • Infine, una volta che tutti i blocchi sono stati controllati, la funzione distruggerà ogni blocco contrassegnato come una corrispondenza.

Per prima cosa, abbiamo bisogno di un evento che possa iterare attraverso ciascuno Bloccare. Il modo in cui ho costruito il sistema, itera effettivamente attraverso i blocchi due volte: una volta per verificare le corrispondenze verticali e una volta per verificare le corrispondenze orizzontali. A seconda di quale controllo sta facendo, userà una funzione diversa per cercare effettivamente la corrispondenza.

La prima cosa che dobbiamo fare è fare un Variabile globale per tenere traccia di quanti blocchi di corrispondenza abbiamo trovato in una determinata iterazione:

Nome variabile globale: "NumMatchesFound" Tipo = Numero Valore = 0

Ora, facciamo il Evento che itererà attraverso i blocchi:

Evento: Funzione> On function Nome: "FindMatches" Sotto-evento: Sistema> Per ogni oggetto: Block Azione: Sistema> Imposta valore NumMatchesFound = 1 Azione: Funzione> Funzione chiamata Nome: "CheckMatchesX" Parametro 0: Block.X Parametro 1 : Block.Y Parametro 2: Block.Color Evento secondario: Sistema> Confronta variabile NumMatchesFound> = 3 Azione: Blocca> Imposta Booleano IsMatched = True Sotto-evento: Sistema> Per ogni oggetto: Blocca Azione: Sistema> Imposta valore NumMatchesFound = 1 Azione: Funzione> Funzione chiamata Nome: "CheckMatchesY" Parametro 0: Block.X Parametro 1: Block.Y Parametro 2: Block.Color Evento secondario: Sistema> Confronta variabile NumMatchesFound> = 3 Azione: Block> Imposta Boolean IsMatched = True Sub-Event: Block> Is Boolean set di variabili d'istanza System> Wait Second = 0.1 Block> Destroy

Il tuo codice dovrebbe assomigliare a questo:


In questo evento, iteriamo attraverso ogni blocco e inviandoli CheckMatchesX o CheckMatchesY, le funzioni che controlleranno se il blocco adiacente è una corrispondenza.

Per inviare il blocco nella funzione, passiamo le funzioni tre diversi parametri:

  • Parametro 0 è la posizione X del blocco
  • Parametro 1 è la posizione Y del blocco
  • Parametro 2 è il colore.

Dopo che ciascun blocco viene inviato in una delle funzioni e la funzione termina, verifica NumMatchesFound per vedere se ha trovato tre o più blocchi corrispondenti, quindi etichetta i blocchi come Matched se lo facesse.

Infine, ogni blocco contrassegnato come essere Matched viene distrutto dopo che sono trascorsi 0,1 secondi. Questo aspettare l'affermazione è lì per permettere al gioco di cambiare le immagini dei Blocks per l'immagine che indica che sono abbinati, e di dare al giocatore un momento per notare questo cambiamento.

(Mentre si potrebbe rimuovere il aspettare dichiarazione senza influire negativamente sul gameplay, rende più semplice la comprensione per il giocatore, e rallenta il gioco quel tanto che basta affinché il giocatore possa facilmente tenere traccia di ciò che sta accadendo.)


2. Le due funzioni di controllo

Quindi dobbiamo fare il CheckMatchesX e CheckMatchesY funzioni. Queste funzioni funzioneranno in modo simile agli iteratori sopra, in quanto ci sarà una versione per il controllo delle corrispondenze orizzontali, CheckMatchesX, e uno per le partite verticali, CheckMatchesY.

Controlli orizzontali

Per prima cosa, costruiamo la funzione di controllo orizzontale:

Evento: Funzione> On function Nome: "CheckMatchesX" Sotto-evento: Condizione: Block> Compare XX = Function.Param (0) + (Block.Width + 2) Condizione: Block> Compare YY = Function.Param (1) Condizione : Blocca> Confronta variabile di istanza Colore = Funzione.Param (2) Azione: Sistema> Aggiungi a Variabile = NumBlocks Valore = 1 Azione: Funzione> Funzione chiamata Nome: "CheckMatchesX" Parametro 0: Function.Param (0) + (Block. Width + 2) Parametro 1: Function.Param (1) Parametro 2: Function.Param (2) Sotto-evento: System> Compare Variable NumMatchesFound> = 3 Azione: Block> Set Boolean IsMatched = True

Il tuo codice dovrebbe assomigliare a questo:


Quindi, cosa sta facendo questa funzione?

  • Innanzitutto, verifica se esiste un blocco vicino alla sinistra del blocco in cui siamo passati.
  • Una volta che la funzione conferma che c'è un blocco nella posizione vicina, controlla se è dello stesso colore del blocco in cui siamo passati.
  • Se lo è, aumenta NumMatchesFound da uno, e passa il blocco appena trovato nella funzione proprio come ha fatto per l'originale.
  • Questo continua fino a quando non trova un blocco che non è dello stesso colore dell'originale. A quel punto controlla se ha trovato abbastanza blocchi di corrispondenza per creare un gruppo e etichetta i blocchi come corrispondenze se lo ha fatto.

Verifiche verticali

Ora, facciamo un'altra versione di questa funzione che farà la stessa cosa per le corrispondenze verticali. Questo sarà il nostro CheckMatchesY funzione. Puoi copiare la funzione originale e apportare tutte le modifiche appropriate, o semplicemente ricostruirla da zero; in entrambi i casi, ecco come deve apparire la tua funzione quando è finita:

Evento: Funzione> On function Nome: "CheckMatchesY" Evento secondario: Condition: Block> Compare XX = Function.Param (0) Condizione: Block> Compare YY = Function.Param (1) + (Block.Width + 2) Condizione : Blocca> Confronta variabile di istanza Colore = Funzione.Param (2) Azione: Sistema> Aggiungi a Variabile = NumBlocks Valore = 1 Azione: Funzione> Funzione di chiamata Nome: "CheckMatchesY" Parametro 0: Function.Param (0) Parametro 1: Funzione .Param (1) + (Block.Width + 2) Parametro 2: Function.Param (2) Sotto-evento: Sistema> Confronta variabile NumMatchesFound> = 3 Azione: Blocco> Imposta booleano IsMatched = True

Il tuo codice dovrebbe assomigliare a questo:



3. In realtà alla ricerca di assegni

Infine, dobbiamo effettivamente chiamare il FindMatches funzione. Vai al SwapBlocks funzione e aggiungi un nuovo sotto-evento alla fine della funzione:

Evento: Funzione> Sotto-evento: Azione: Funzione> Funzione chiamata Nome: "FindMatches"

Noterai che questo sotto-evento in realtà non ha alcuna condizione. Se non hai mai fatto un evento secondario come questo prima, crea un evento secondario con qualsiasi condizione, poiché richiede di dare una condizione quando si effettua un evento secondario, quindi eliminare la condizione, ma lasciare il sub-evento. In questo modo, ti assicuri che l'evento secondario funzioni sempre.

Il tuo SwapBlocks l'evento dovrebbe ora assomigliare a questo:

Se esegui il gioco a questo punto, vedrai che i blocchi vengono distrutti quando si verificano le partite. Noterai anche che le partite che sono lì quando il gioco inizia non scompaiono finché non fai uno scambio di qualche tipo. Questo perché non chiamiamo mai il FindMatches funzione dopo aver creato la griglia di blocchi.

Il motivo per cui non abbiamo aggiunto questo codice è perché nella versione finale ci sarà un'altra funzione che impedisce che le partite vengano generate automaticamente come questa, quindi non c'è davvero alcun motivo per preoccuparsi di questo problema. (Ma sentiti libero di chiamare il FindMatches funzione in precedenza, se ti piace.)


4. Consolidare i controlli

A questo punto, abbiamo un sistema di corrispondenza abbastanza forte, ma il problema è che il nostro codice è ridondante. Attualmente, abbiamo due funzioni diverse che controllano se c'è un vicino corrispondente, e l'unica differenza tra loro è che uno controlla verticalmente, e l'altro controlla orizzontalmente.

Poiché la versione gratuita di Construct 2 limita il numero di eventi che possiamo avere, questo è sicuramente uno spreco. Per risolvere questo, creeremo una nuova versione della funzione che può fare entrambi i controlli.

Se osservi la funzione, vedrai che l'unica differenza tra le due versioni è quella che aggiunge Block.Width + 2 alla posizione x del blocco, e l'altro lo aggiunge alla posizione y della Bock. Quindi, l'ostacolo che dobbiamo superare per rendere questa una singola funzione, sta dando alla funzione un modo per aggiungere Block.Width + 2 solo X, o solo Y, senza usando un Se dichiarazione o più funzioni, poiché richiedono più eventi da eseguire.

La mia soluzione a questo non è molto complessa, ma sarà più facile capire se possiamo vederla venire insieme, quindi la implementeremo e spiegherò come funziona una volta che possiamo vederlo tutto in azione.

  1. Elimina il CheckMatchesY evento.
  2. Rinominare il CheckMatchesX evento a, semplicemente, CheckMatches.
  3. Nella chiamata di funzione per CheckMatchesX sotto il FindMatches evento:
    1. Modifica la chiamata alla funzione per essere CheckMatches invece di CheckMatchesX.
    2. Inserisci Parametro 3.
      1. Valore = 1.
    3. Inserisci Parametro 4.
      1. Valore = 0.
  4. Nella chiamata di funzione per CheckMatchesY sotto il FindMatches evento:
    1. Modifica la chiamata alla funzione per essere CheckMatches invece di CheckMatchesY.
    2. Inserisci Parametro 3.
      1. Valore = 0.
    3. Inserisci Parametro 4.
      1. Valore = 1.

Come spiegherò presto, questi parametri aggiunti diranno CheckMatches se sta facendo un controllo orizzontale o un controllo verticale. Quando ci mandiamo 1 per Parametro 3, e 0 per Parametro 4, è un assegno orizzontale e quando lo spediamo 0 per Parametro 3, e 1 per Parametro 4, è un controllo verticale.

Ora, torna al CheckMatches funzione, e modificare le condizioni e le azioni per assomigliare a questo:

Evento: Funzione> Funzione On Nome: Sub-evento "CheckMatches": Condizione: Blocco> Confronta XX = Funzione.Param (0) + ((Block.Width + 2) * Funzione.Param (3)) Condizione: Blocco> Confronta YY = Function.Param (1) + ((Block.Width + 2) * Function.Param (4)) Condizione: Block> Confronta la variabile di istanza Color = Function.Param (2) Azione: Block> Set Boolean IsMatched = True Action : Funzione> Funzione chiamata Nome: "CheckMatches" Parametro 0: Function.Param (0) + ((Block.Width + 2) * Function.Param (3)) Parametro 1: Function.Param (1) + ((Block. Larghezza + 2) * Funzione.Param (4)) Parametro 2: Function.Param (2) Parametro 3: Function.Param (3) Parametro 4: Function.Param (4) Sotto-evento: Sistema> Confronta variabile NumMatchesFound> = 3 Azione: Blocca> Imposta Booleano IsMatched = True

Questo è ciò che è tuo FindMatches e CheckMatches il codice dovrebbe ora apparire come:


Come funziona?

Quindi, che cosa sta facendo questa nuova versione della funzione?

Bene, ogni volta che chiami CheckMatches ora invii altri due parametri, anziché aggiungere Block.Width + 2 alla posizione x- o y, sta aggiungendo (Block.Width + 2) * Function.Param (3) alla posizione x, e (Block.Width + 2) * Function.Param (4) alla posizione y.

Poiché uno di questi due parametri sarà sempre 1, e l'altro sarà sempre 0, questo significa che la posizione x- o y sarà modificata, mai entrambe le cose!

Per esempio, se ci inoltriamo 1 per Parametro 3, e 0 per Parametro 4, poi aggiunge (Block.Width + 2) * 1, che è semplicemente Block.Width + 2, alla posizione x, e (Block.Width + 2) * 0, che è 0, alla posizione y.

Ecco un rapido esempio per mostrare cosa intendo e come calcola la posizione del blocco in cui controllerà la corrispondenza. Diciamo che in questo esempio il blocco originale è a (200, 200), e i blocchi hanno una larghezza di 40. Quindi, se vogliamo ottenere la posizione del blocco verticale adiacente, le formule funzioneranno in questo modo:

  • X = 200 + ((Block.Width + 2) * 0) = 200 + (40 + 2) * 0 = 200 + 0 = 200
  • Y = 200 + ((Block.Width + 2) * 1) = 200 + (40 + 2) * 1 = 200 + 42 = 242

Se volessimo ottenere la posizione del blocco orizzontale vicino, le formule funzionerebbero in questo modo:

  • X = 200 + ((Block.Width + 2) * 1) = 200 + (40 + 2) * 1 = 200 + 42 = 242
  • Y = 200 + ((Block.Width + 2) * 0) = 200 + (40 + 2) * 0 = 200 + 0 = 200

Se esegui il gioco ora, dovresti vedere che il sistema di corrispondenza funziona ancora come inizialmente, ma dal nostro punto di vista, è in realtà un sistema migliore.


Conclusione

A questo punto la nostra funzione di rilevamento delle corrispondenze è ancora incompleta, ma abbiamo già fatto molto in questo tutorial e penso che sia importante lasciare che tutto questo si affondi prima di aggiungere qualcos'altro. Con questo in mente, ho intenzione di concludere questo articolo qui. Guarda la demo nella sua forma attuale.

Nel prossimo articolo aggiungeremo un sistema di punti, miglioreremo il sistema di corrispondenza e aggiungeremo "gravità" in modo che i blocchi cadano quando i blocchi sottostanti vengono eliminati.

Se vuoi ottenere un vantaggio sul prossimo articolo, prenditi un po 'di tempo per considerare come rileveresti quando c'è uno spazio vuoto sotto un blocco. Prova a guardare il Blocco> È sovrapposto all'offset funzione per l'ispirazione!