Tot nu toe heeft deze serie de basis besproken van het opzetten van een Match-3-game en het implementeren van de eerste gameplay-elementen zoals block-swapping. In deze zelfstudie gaan we verder bouwen op dit alles en beginnen met het detecteren wanneer de speler een overeenkomst heeft gemaakt.
Hier is een demo van de game waaraan we werken in deze serie:
Voorlopig gaan we alleen een basisversie van het matching-systeem implementeren, met de nadruk op het vinden van overeenkomsten en het vernietigen van gematchte blokken. In latere artikelen zullen we doorgaan met het ontwikkelen en doorvoeren van het systeem.
Tip: Je moet lezen hoe een recursieve functie werkt, als je dat nog niet weet; in wezen is het een functie die zichzelf roept. Recursieve functies kunnen op dezelfde manier werken als loops, maar omdat ze ook variabelen kunnen opnemen en retourneren, hebben ze veel meer toepassingen dan lussen doen.
Net als bij de vorige tutorial wil ik eerst bespreken hoe het systeem zal werken en vervolgens proberen het te bouwen.
Blok
voorwerp. Blok
, het geeft de kleur en positie van het blok waarin het kijkt naar een recursieve functie door, die naar de horizontale of verticale buur kijkt en bepaalt of ze dezelfde kleur hebben. Op elkaar afgestemd
met de IsMatched
instantievariabele die we in een van de vorige tutorials hebben gemaakt; anders doet het niets. Ten eerste hebben we een gebeurtenis nodig die elk kan doorlopen Blok
. De manier waarop ik het systeem heb gebouwd, itereert feitelijk door de blokken heen tweemaal: eenmaal om te controleren op verticale overeenkomsten en eenmaal om te controleren op horizontale overeenkomsten. Afhankelijk van welke check het doet, zal het een andere functie gebruiken om daadwerkelijk naar de match te zoeken.
Het allereerste dat we moeten doen is een maken Globale variabele om bij te houden hoeveel overeenkomende blokken we hebben gevonden in een bepaalde iteratie:
Global Variable Name: "NumMatchesFound" Type = Number Value = 0
Laten we nu het maken Evenement dat zal door de blokken heen gaan:
Gebeurtenis: Functie> Aan functie Naam: "FindMatches" Subgebeurtenis: Systeem> Voor elk object: Blokkering Actie: Systeem> Stel waarde in NumMatchesFound = 1 Actie: Functie> Oproepfunctie Naam: "CheckMatchesX" Parameter 0: Block.X Parameter 1 : Block.Y Parameter 2: Block.Color Sub-Event: System> Compare Variable NumMatchesFound> = 3 Action: Block> Set Boolean IsMatched = True Sub-Event: System> For each Object: Block Action: System> Stel value in NumMatchesFound = 1 Actie: Functie> Oproepfunctie Naam: "CheckMatchesY" Parameter 0: Block.X Parameter 1: Block.Y Parameter 2: Block.Color Sub-gebeurtenis: Systeem> Vergelijk variabele NumMatchesFound> = 3 Actie: Blokkeren> Set Boolean IsMatched = Echte subgebeurtenis: Blokkeren> Is Boolean-instantievariabele ingesteld Systeem> Tweede wacht = 0,1 Blokkering> Vernietigen
Uw code zou er als volgt uit moeten zien:
In dit geval herhalen we elk blok en sturen we het naar binnen CheckMatchesX
of CheckMatchesY
, de functies die zullen controleren om te zien of het naburige blok een overeenkomst is.
Om het blok naar de functie te sturen, geven we de functies drie verschillende parameters door:
Nadat elk blok naar een van de functies is verzonden en de functie is voltooid, controleert het NumMatchesFound
om te zien of het drie of meer overeenstemmende blokken heeft gevonden en vervolgens de blokken als een label geeft Op elkaar afgestemd
als dat zo was.
Eindelijk, elk blok dat is gemarkeerd als zijnde Op elkaar afgestemd
wordt vernietigd na 0,1 seconden. Deze Wacht
verklaring is er om het spel toe te staan om de afbeeldingen voor de blokken naar de afbeelding te schakelen die aangeven dat ze gematcht zijn, en om de speler een moment te geven om deze verandering op te merken.
(Terwijl u de Wacht
verklaring zonder een negatief effect op het spel te hebben, het maakt de overeenkomst gemakkelijker voor de speler om te begrijpen, en vertraagt het spel net genoeg, zodat de speler gemakkelijk kan bijhouden wat er gaande is.)
Vervolgens moeten we de CheckMatchesX
en CheckMatchesY
functies. Deze functies werken op dezelfde manier als de bovenstaande iterators, in die zin dat er één versie is voor het controleren van horizontale overeenkomsten, CheckMatchesX
, en één voor verticale overeenkomsten, CheckMatchesY
.
Laten we eerst de horizontale controlefunctie bouwen:
Gebeurtenis: Functie> Aan functie Naam: "CheckMatchesX" Subgebeurtenis: Voorwaarde: Blok> Vergelijk XX = Functie.Param (0) + (Blok.breedte + 2) Voorwaarde: Blok> Vergelijk YY = Functie.Param (1) Voorwaarde : Block> Vergelijk instantievariabele Color = Function.Param (2) Actie: Systeem> Toevoegen aan variabele = NumBlocks Waarde = 1 Actie: Functie> Oproepfunctie Naam: "CheckMatchesX" Parameter 0: Function.Param (0) + (Block. Width + 2) Parameter 1: Function.Param (1) Parameter 2: Function.Param (2) Subgebeurtenis: Systeem> Vergelijk variabele NumMatchesFound> = 3 Actie: Blokkeren> Set Boolean IsMatched = True
Uw code zou er als volgt uit moeten zien:
Dus, wat doet deze functie??
NumMatchesFound
door een, en geeft het nieuw gevonden Blok in de functie, net zoals het deed voor het origineel.Laten we nu een andere versie van deze functie maken die hetzelfde zal doen voor verticale overeenkomsten. Dit wordt onze CheckMatchesY
functie. Je kunt de originele functie kopiëren en alle benodigde wijzigingen aanbrengen, of gewoon helemaal opnieuw bouwen; in beide gevallen is dit de manier waarop uw functie eruit moet zien als deze is voltooid:
Gebeurtenis: Functie> Aan functie Naam: "CheckMatchesY" Subgebeurtenis: Voorwaarde: Blokkering> Vergelijk XX = Functie.Param (0) Voorwaarde: Blokkering> Vergelijk YY = Function.Param (1) + (Block.Width + 2) Conditie : Block> Vergelijk instantievariabele Color = Function.Param (2) Actie: Systeem> Toevoegen aan variabele = NumBlocks Waarde = 1 Actie: Functie> Oproepfunctie Naam: "CheckMatchesY" Parameter 0: Function.Param (0) Parameter 1: Functie .Param (1) + (Block.Width + 2) Parameter 2: Function.Param (2) Subgebeurtenis: Systeem> Vergelijk variabele NumMatchesFound> = 3 Actie: Blokkeren> Set Boolean IsMatched = True
Uw code zou er als volgt uit moeten zien:
Eindelijk moeten we het FindMatches
functie. Ga naar de SwapBlocks
functie en voeg een nieuw subgebeurtenis toe aan het einde van de functie:
Gebeurtenis: Functie> Subgebeurtenis: Actie: Functie> Oproepfunctie Naam: "FindMatches"
Je zult merken dat dit sub-evenement eigenlijk geen voorwaarden bevat. Als u nog nooit eerder een dergelijk subgebeurtenis heeft gemaakt, maakt u gewoon een subgebeurtenis met welke voorwaarde dan ook, omdat u een voorwaarde moet opgeven bij het maken van een subgebeurtenis en vervolgens de voorwaarde moet verwijderen, maar de sub-event. Op deze manier zorgt u ervoor dat het sub-evenement altijd wordt uitgevoerd.
Jouw SwapBlocks
evenement zou er nu als volgt uit moeten zien:
Als je het spel nu uitvoert, zie je dat de blokken worden vernietigd wanneer matches optreden. Je zult echter ook merken dat alle matches die er zijn wanneer het spel begint niet verdwijnen totdat je een of andere ruil doet. Dit komt omdat we nooit de FindMatches
functie nadat we het raster met blokken hebben gemaakt.
De reden dat we deze code niet hebben toegevoegd, is omdat in de definitieve versie er een andere functie is die voorkomt dat overeenkomsten op deze manier automatisch worden gegenereerd, dus er is echt geen reden om je zorgen te maken over dit probleem. (Maar voel je vrij om de. Te bellen FindMatches
eerder functioneren, als je wilt.)
Op dit moment hebben we een behoorlijk sterk matchingsysteem, maar het probleem is dat onze code overbodig is. Momenteel hebben we twee verschillende functies die controleren of er een overeenkomende buur is en het enige verschil tussen beide is dat de ene verticaal wordt gecontroleerd en de andere horizontaal wordt gecontroleerd.
Omdat de gratis versie van Construct 2 het aantal evenementen beperkt dat we kunnen hebben, is dit zeker een verspilling. Om dit op te lossen, gaan we een nieuwe versie van de functie maken die beide controles kan uitvoeren.
Als u naar de functie kijkt, ziet u dat het enige verschil tussen de twee versies is dat er een wordt toegevoegd Block.Width + 2
naar de x-positie van het Blok en de andere voegt het toe aan de y-positie van de Bock. Dus het obstakel dat we moeten overbruggen om dit een enkele functie te maken, is de functie een manier geven om toe te voegen Block.Width + 2
alleen X
, of alleen Y
, zonder met behulp van een Als
verklaring of meerdere functies, omdat die meer gebeurtenissen vereisen die moeten worden uitgevoerd.
Mijn oplossing hiervoor is niet erg ingewikkeld, maar het zal gemakkelijker te begrijpen zijn als we het samen kunnen zien, dus we zullen het implementeren, en ik zal uitleggen hoe het werkt zodra we het allemaal in actie kunnen zien.
CheckMatchesY
evenement.CheckMatchesX
evenement, eenvoudig, CheckMatches
.CheckMatchesX
onder de FindMatches
evenement: CheckMatches
in plaats van CheckMatchesX
.Parameter 3
. 1
.Parameter 4.
0
.CheckMatchesY
onder de FindMatches
evenement: CheckMatches
in plaats van CheckMatchesY
.Parameter 3
. 0
.Parameter 4
. 1
.Zoals ik binnenkort zal uitleggen, zullen deze toegevoegde parameters het leren CheckMatches
of het een horizontale controle of een verticale controle doet. Wanneer we insturen 1
voor Parameter 3
, en 0
voor Parameter 4
, het is een horizontale controle en wanneer we insturen 0
voor Parameter 3
, en 1
voor Parameter 4
, het is een verticale controle.
Ga nu terug naar de CheckMatches
functie, en wijzig de voorwaarden en acties om er als volgt uit te zien:
Evenement: Functie> Aan functie Naam: "CheckMatches" Subgebeurtenis: Voorwaarde: Blokkering> Vergelijk XX = Functie.Param (0) + ((Block.Width + 2) * Function.Param (3)) Conditie: Blokkering> Vergelijken YY = Functie.Param (1) + ((Block.Width + 2) * Function.Param (4)) Voorwaarde: Blok> Vergelijk exemplaarvariabele Color = Function.Param (2) Actie: Blokkeren> Boolean IsMatched instellen = True Action : Functie> Oproepfunctie Naam: "CheckMatches" Parameter 0: Function.Param (0) + ((Block.Width + 2) * Function.Param (3)) Parameter 1: Function.Param (1) + (Blok. Width + 2) * Function.Param (4)) Parameter 2: Function.Param (2) Parameter 3: Function.Param (3) Parameter 4: Function.Param (4) Subgebeurtenis: Systeem> Variabele NumMatches vergelijken Gevonden> 3 Action: Block> Set Boolean IsMatched = True
Dit is wat jouw FindMatches
en CheckMatches
code zou er nu moeten uitzien als:
Dus, wat is deze nieuwe versie van de functie eigenlijk aan het doen?
Wel, als je belt CheckMatches
je stuurt nu nog twee parameters, en in plaats van toe te voegen Block.Width + 2
naar de x- of de y-positie, het is toevoegen (Block.Width + 2) * Function.Param (3)
naar de x-positie, en (Block.Width + 2) * Function.Param (4)
naar de y-positie.
Omdat een van die twee parameters altijd zal zijn 1
, en de ander zal altijd zijn 0
, dit betekent dat ofwel de x- ofwel de y-positie zal worden gewijzigd - nooit beide!
Bijvoorbeeld als we binnengaan 1
voor Parameter 3
, en 0
voor Parameter 4
, dan voegt het toe (Block.Width + 2) * 1
, wat eenvoudig is Block.Width + 2
, naar de x-positie, en (Block.Width + 2) * 0
, welke is 0
, naar de y-positie.
Hier is een snel voorbeeld om te laten zien wat ik bedoel en hoe het de positie berekent van het blok waar het naar de wedstrijd zal kijken. Laten we zeggen dat in dit voorbeeld het originele blok aanwezig is (200, 200)
, en de blokken hebben een breedte van 40
. Dus als we de positie van het aangrenzende verticale blok willen weten, werken de formules als volgt:
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
Als we de positie van het aangrenzende horizontale blok wilden bereiken, zouden de formules als volgt werken:
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
Als je het spel nu uitvoert, zou je moeten zien dat het match-systeem nog steeds werkt zoals het oorspronkelijk deed, maar vanuit ons perspectief is het eigenlijk een beter systeem.
Op dit punt is onze matchdetectiefunctie nog steeds onvolledig, maar we hebben al veel gedaan in deze tutorial en ik denk dat het belangrijk is om dit allemaal te laten inzinken voordat we iets anders toevoegen. Met dat in gedachten, ga ik hier dit artikel beëindigen. Bekijk de demo in zijn huidige vorm.
In het volgende artikel zullen we een puntensysteem toevoegen, we zullen het koppelingssysteem verbeteren, en we zullen "zwaartekracht" toevoegen zodat de blokken vallen wanneer blokken eronder worden geëlimineerd.
Als u een voorsprong wilt nemen op het volgende artikel, moet u even nadenken over hoe u zou kunnen detecteren wanneer er een lege ruimte onder een blok is. Kijk eens naar de Blokkeren> overlapt overlappend
functie voor inspiratie!