Lag et Match-3-spill i Construct 2 Eliminere ferdige kampene

I den forrige opplæringen fikk vi endelig spillet vårt og flyttet til våre blokker. På toppen av det opprettet vi et rudimentært vanskelighetssystem for å gjøre spillet vanskeligere når spilleren spiller lenger.

Med begge disse funksjonene i spillet, er vi klare til å implementere systemet som vil eliminere forhåndsdefinerte kamper fra brettet. Selv om dette ikke er den siste artikkelen i serien, er dette det siste store systemet vi trenger å implementere - så bli komfortabel, fordi vi har vårt arbeid skåret ut for oss.


Final Game Demo

Her er en demonstrasjon av spillet vi jobber med i denne serien:




Raskreparasjoner

Før vi begynner med hoveddelen av denne opplæringen, vil jeg ta et minutt for å fikse to problemer jeg oppdaget mens jeg skrev den forrige opplæringen.

Matchende

Det første problemet jeg refererer til kommer opp i scenariet du kan se nedenfor:

I denne situasjonen, hvis du drar Blokk B På den grønne prikken, bør den falle på grunn av de tomme stedene under prikken, og til slutt lande i stedet merket C. I de fleste scenarier vil dette skje, og spillet vil fungere normalt, men i noen scenarier vil spillet i stedet oppdage en kamp i kort øyeblikk hvor Blokk B er ved siden av gruppen EN og det vil ende med å ødelegge alle tre blokkene.

Dette problemet er ikke eksklusivt for dette scenariet ovenfor, og kan også presentere seg når du gjør det samme i scenariet jeg har uthevet nedenfor.

Hvis vi ikke løser dette, vil spilleren motta kreditt og poeng for en rekke kamper de aldri hadde til hensikt å gjøre, og kan også bli forvirret om hvorfor så mange blokker forsvinner uventet.

Heldigvis er dette et enkelt problem å fikse. For å løse dette problemet skal vi lage en ny Global variabel kalt MatchesPossible som vil diktere om kampene kan bli laget, og en ny hendelse som vil oppdage når en blokk er "fallende" og vil modifisere MatchesPossible for å gjøre det slik at ingen kamper kan gjøres mens dette skjer.

Først vil vi opprette Global Variable:

Global Variabel: MatchesPossible Type = Antall Initial Value = 1

Din nye variabel skal se slik ut:

Nå skal vi lage arrangementet som vil lytte etter når en blokk faller:

Begivenhet: Tilstand: Inverter: Blokk> Overlapper mot offset Objekt = Blokk Offset X = 0 Offset Y = 8 Tilstand: Blokk> Sammenlign Y Sammenligning = Mindre eller lik Y-koordinat = SPAWNY Handling: System> Angi verdi Variabel = MatchesPossible Verdi = 1

Denne hendelsen gjør det slik at når en blokk er funnet å ha en tom plass under den MatchesPossible er satt til 1, meningene samsvarer ikke. Du vil også legge merke til at den kontrollerer blokkens Y-posisjon. Dette er for å sikre at blokken ikke ligger på den nederste raden av blokker som alltid vil ha tom plass under den.

Deretter trenger vi en hendelse som setter MKatchesPossible tilbake til 0 når ingen blokker har en tom plass under dem. Denne andre hendelsen skal være basert på en annen tilstand:

Hendelse: Tilstand: System> Øvrig handling: System> Angi verdi Variabel = MatchesPossible Verdi = 0

Pass på at denne hendelsen umiddelbart følger den første hendelsen slik at Else-setningen blir brukt riktig.

Dine to nye arrangementer skal se slik ut:

Til slutt skal vi legge til en ny betingelse for CheckMatches slik at den ser på MatchesPossible for å avgjøre om en kamp kan gjøres. Legg til denne tilstanden til den første funksjonen til CheckMatches Begivenhet.

Tilstand: System> Sammenlign variabel variabel = MatchesPossible Comparison = Lik til Vale = 0

Med tilstanden lagt til, din CheckMatches Hendelsen skal nå se slik ut:

I motsetning til de fleste problemene vi har møtt opp til dette punktet, oppstår dette problemet på en ganske inkonsekvent måte. Dette betyr at vi ikke egentlig kan teste for å se om vi løste problemet, vi kan bare teste for å se om vi har forårsaket andre problemer. Hvis du spiller spillet nå, bør du se at ingen nye problemer har blitt forårsaket av denne tilstanden.

Poeng

Det andre problemet jeg ønsket å fikse før vi legger til noe nytt, er knyttet til Points-systemet.

Mens jeg jobbet på prosjektet for denne opplæringen, la jeg merke til at noe jeg gjorde gjorde at Points-systemet skulle oppføre seg merkelig og gi spilleren fire eller fem ganger så mange poeng som de burde få for hver kamp. Selv om jeg ikke var i stand til å bestemme hvilken endring jeg gjorde, forårsaket dette å begynne å skje, fant jeg ut at roten til problemet var at GivePoints funksjonen ble faktisk kalt flere ganger siden blokkene ikke ble ødelagt umiddelbart. Heldigvis, som vår siste utgave, kan dette løses enkelt.

For å fikse dette skal vi lage en ny variabel som vil fortelle systemet om det kan gi poeng. Så når vi skal bruke GivePoints funksjon vil vi også endre variabelen for å sikre at hendelsen bare brenner en gang. Til slutt, når poengene er gitt, vil vi endre variabelen en gang til, slik at det ikke kommer et problem neste gang vi prøver å gi poeng.

Først opprett en global variabel som heter PointsGiven:

Global Variabel: PointsGiven Type = Antall Initial Value = 0

Din variabel skal slik:

Neste vil vi endre delen av FindMatches funksjon som faktisk gir poengene ved å legge til en ny betingelse og to nye handlinger.

Tilstand: System> Sammenlign variabel Variabel = PointGiven Sammenligning = Likeverdig = 0

Legg nå denne handlingen til begynnelsen av handlingslisten:

Handling: System> Angi verdi Variabel = PointsGiven Verdi = 1

Til slutt legger du til denne handlingen til slutten av handlingslisten:

Handling: System> Angi verdi Variabel = PointsGiven Verdi = 0

Hendelsen skal nå se slik ut:

Med disse endringene har vi gjort det slik at hendelsen som ringer GivePoints vil bare løpe når PointsGiven variabel er 0. Siden vi umiddelbart setter verdien til 1 når vi starter arrangementet, forhindrer dette hendelsen fra å skyte flere ganger og sikrer at spilleren vil motta riktig antall poeng.

Hvis du kjører spillet på dette punktet, bør du motta riktig antall poeng for hver kamp du lager, selv om du ikke hadde dette problemet til å begynne med.


Eliminerer forhåndsdefinerte kamper

Nå som vi har fått disse rettene ut av veien, kan vi fortsette å skape systemet som vil eliminere kamper som er hentet av systemet når det tilfeldigvis tilordnes farger til blokkene det skaper.

Problemet vi har nå er at siden Block-fargene er helt tilfeldige, er det ikke uvanlig at du starter spillet og ser en haug med kamper som blir gjort umiddelbart. Dette er et problem fordi det kan gjøre de første par sekunder av spillet veldig forvirrende for noen som aldri har spilt før, og fordi det gir spilleren poeng de ikke tjente.

For å løse problemet, oppretter vi en funksjon som vil se på hver blokk og deretter se om den blokken har samme farge som noen av naboene. Hvis det er samme farge som en nabo, fortsetter den å endre fargen til den aktuelle blokken til den ikke lenger samsvarer med noen av blokkene som omgir den.

For å få dette systemet til å virke, må vi også opprette flere støttefunksjoner og hendelser, og legge til en ny instansvariabel til Blokkere gjenstand.

Gjør det til jobb

Først oppretter du en ny instansvariabel for Blokkere gjenstand:

Instansvariabel: BlockID Type = Antall Initial verdi = 0

Denne variabelen er det vi skal bruke for å enkelt identifisere en blokk slik at vi kan fortelle noen av funksjonene vi skal lage nøyaktig hvilken blokk vi vil se på, uavhengig av posisjonen.

Før vi går videre, må vi også begynne å bruke denne variabelen. Gå til På begynnelsen av oppsettet Hendelse som lager blokkene og legger til en ny handling før handlingen som øker NumBlocks:

Handling: Blokk> Angi verdi Instansvariabel = BlockID Value = NumBlocks

Din blokkgytningshendelse skal nå se slik ut:

Neste må vi lage en funksjon som vil ta i X- og Y-posisjonen til en blokk og fortelle oss hvilken farge den blokken er:

Hendelse: Tilstand: Funksjon> På funksjon Navn = "GetBlockColor" Sub-Event: Tilstand: Blokk> Sammenlign X Sammenligning = Lik til X-koordinat = Funksjon.Param (0) Tilstand: Blokk> Sammenlign Y Sammenligning = Lik til Y co -ordinate = Function.Param (0) Handling: Funksjon> Angi returverdi Verdi = Block.Color Sub-Event: System> Annet handling: Funksjon> Angi returverdi Verdi = -1

Funksjonen skal se slik ut når den er ferdig:

Nå som vi har en funksjon som kan fortelle oss fargen på en blokk, skal vi lage den funksjonen som faktisk vil se på en blokk og avgjøre om den har naboblokker som har samme farge.

Måten denne funksjonen vil fungere på, er ganske enkel.

  • Først vil vi passere en BlockID inn i funksjonen.
  • Hvis det for tiden er en blokk med det BlockID, funksjonen vil se på de fire nærliggende blokkene, og vil avgjøre om blokken den ser på, er den samme fargen som noen av sine naboer.
  • Hvis den finner at det er en nabo av samme farge, begynner det å endre fargen på blokken den ser på, og den vil fortsette å endre fargen til Blokken er en annen farge fra alle naboene.

Før vi kan gjøre denne hendelsen, må vi lage en ny global variabel. I funksjonen vil vi bruke en While-loop for å avgjøre om blokkens farge må endres. Variabelen vi skal skape er variabelen mens Loop vil bruke for å avgjøre om den må fortsette å kjøre:

Global Variabel: HasMatchingNeighbor Type = Antall Initial Value = 0

Tips:Hendelsen vi skal lage inneholder en Or-basert Event. Hvis du aldri har laget en Hendelsesblokk som har en Or-attributt alt du trenger å gjøre, er å gjøre Hendelsesblokken som du normalt ville og da høyreklikke hele blokken og velg Lag 'Eller' Blokk. I motsetning til en standardbegivenhetsblokk som krever at alle forhold fylles før det brenner, vil en eller blokk brenne hvis noen tilstanden er oppfylt.

Så la oss gjøre arrangementet:

Hendelse: Tilstand: Funksjon> På funksjon Navn = "RemoveSpawnedMatches" Sub-Event: Tilstand: Blokk> Sammenlign instansvariabel Instansvariabel = BlockID-sammenligning = Likeverdig = Function.param (0) Handling: System> Angi verdi Variabel = HasMatchingNeighbor Value = 1 Sub-Event: Tilstand: System> Mens tilstand: System> Sammenlign variabel Variabel = HasMatchingNeighbor Comparison = Likeverdig = 1 Sub-Event: Tilstand: Blokk> Sammenlign instansvariabel Instansvariabel = Fargekomparison = Likeverdig = Funksjon. Ring ("GetBlockColor", Block.X - (Block.Width + 2), Block.Y) Handling: Blokk> Angi verdi Instansvariabel = Fargeverdi = gulv (Tilfeldig (1,7)) Handling: System> Angi verdi Variabel = HasMatchingNeighbor Value = 1 Sub-Event: Tilstand: System> Annet Tilstand: Blokk> Sammenlign instansvariabel Instansvariabel = Fargekomparison = Likeverdig = Function.Call ("GetBlockColor", Block.X + (Block.Width + 2) , Block.Y) Handling: Blokk> Angi verdi Instansvariabel = Fargeverdi = gulv (Tilfeldig (1,7)) Handling: System> Angi verdi Variabel = HasMatchingNeighbor Value = 1 Sub-Event: Tilstand: System> Annet tilstand: Blokk> Sammenlign instansvariabel Instansvariabel = Fargekomparison = Likeverdig = Function.Call ("GetBlockColor", Block.X, Block.Y - (Block.Width + 2)) Handling: Blokk> Angi verdi Instansvariabel = Fargeverdi = gulv (Tilfeldig (1,7)) Handling: System> Angi verdi Variabel = HasMatchingNeighbor Value = 1 Sub-Event: Tilstand : System> Annet tilstand: Blokk> Sammenlign instansvariabel Instansvariabel = Fargekomparison = Likeverdig = Funksjon.Kall ("GetBlockColor", Block.X, Block.Y + (Block.Width + 2)) Handling: Blokk> Sett verdi Instansvariabel = Fargeverdi = gulv (Tilfeldig (1,7)) Handling: System> Angi verdi Variabel = HasMatchingNeighbor Value = 1 Sub-Event: Tilstand: System> Annet: System> Angi verdi Variabel = HasMatchingNeighbor Value = 0

Din begivenhet skal se slik ut:


Så hvordan fungerer denne funksjonen nøyaktig?

Den første tingen det gjør er å se etter en Blokkere med BlockID at systemet passerte inn. Når det finner det Blokkere det setter verdien av HasMatchingNeighbors til 1 og kjører deretter While-løkken.

Siden Mens-sløyfen vil bare løpe når HasMatchingNeighbors er 1, det er verdien den setter den til. Under Mens-løkken, tester det for å se om det er en nabo Blokkere til venstre, høyre, over eller under det samme farge som Blokkere vi ser på. Hvis det finner en matchende Blokkere i noen av disse stillingene tildeler den tilfeldig en ny farge til Blokkere og kjører deretter testen igjen ved å sikre HasMatchingNeighbors er satt til 1. Når det endelig finner en farge for Blokkere det stemmer ikke overens med noen av naboene, det endrer verdien av HasMatchingNeighbors til 0 slik at While-sløyfen slutter og programmet kan fortsette.

Nå må vi implementere denne funksjonen i spillet; For å gjøre dette må vi lage to nye variabler og to nye funksjoner. La oss starte med variablene.

Global Variabel: CheckStartingMatches Type = Nummerverdi = 0
Global Variabel: CheckNewestRow Type = Nummerverdi = 0

Dine variabler skal se slik ut:

De to variablene vi nettopp har laget, vil bli brukt til å utløse de to hendelsene vi skal lage. Hendelsene selv vil bli brukt til å iterere gjennom blokkene umiddelbart etter at de er opprettet og sende hver blokk inn i RemoveSpawnedMatches funksjon.

Grunnen til at vi ikke bare ringer til RemoveSpawnedMatches funksjonen umiddelbart etter at blokken er opprettet, er at blokkgitteret må være komplett for at funksjonen skal fungere riktig. Så i stedet for bare å ringe funksjonen direkte når blokkene er laget, vil vi isteden utløse en hendelse som kan gå gjennom blokkene og ringe funksjonen alene etter at gridet er generert.

Den første hendelsen vil være spesielt for iterering gjennom den første gruppen av blokker:

Begivenhet: Tilstand: System> Sammenlign variabel instansvariabel = CheckStartingMatches Sammenligning = Lik til verdi = 1 Tilstand: System> For Navn = "Blokker" Start indeks = 0 Sluttindeks = NumBlocks-1 Handling: Funksjon> Anropsfunksjon Navn = "RemoveSpawnedMatches" Parameter 0 = loopindex ("Blocks") SubEvent: Tilstand: System> Sammenlign to verdier Første verdi = loopindex ("Blocks") Sammenligning = Lige til andre verdi = NumBlocks-1 Handling: System> Angi variabel Instansvariabel = CheckStartingMatches Value = 0

Slik ser hendelsen ut:

Den andre hendelsen vil være spesielt for å sjekke nye rader med blokker når de er laget:

Begivenhet: Tilstand: System> Sammenlign variabel instansvariabel = CheckNewestRow Comparison = Lik til verdi = 1 Tilstand: System> For Navn = "Blokker" Start indeks = NumBlocks-9 End index = NumBlocks-1 Handling: Funksjon> Anropsfunksjon Navn = " RemoveSpawnedMatches "Parameter 0 = loopindex (" Blocks ") SubEvent: Tilstand: System> Sammenlign to verdier Første verdi = loopindex (" Blocks ") Sammenligning = Like til andre verdi = NumBlocks-1 Handling: System> Angi variabel Instansvariabel = CheckNewestRow Value = 0

Dette er hva den andre hendelsen skal se ut som:

Gjennomføring

Med begge disse funksjonene på plass trenger vi nå bare å implementere dem. Gå til den første hendelsen som lager blokkene, den Ved oppstart Begivenhet. Vi skal legge til en underhendelse for dette som vil fortelle CheckStartingMatches Hendelse for å aktivere.

Sub-Event: Condition: System> Sammenlign to verdier Første verdi = loopindex ("X") Sammenligning Andre verdi: 7 Tilstand: System> Sammenlign to verdier Første verdi = loopindex ("Y") Sammenligning Andre verdi: 3 Handling: System> Angi verdi Instans variable = CheckStartingMatches Value = 1

Din begivenhet skal nå se slik ut:

Denne underhendelsen lytter etter når den nestede For-sløyfen er avsluttet, og endrer deretter verdien til CheckStartingMatches variabel for å aktivere den aktuelle hendelsen.

Vi skal nå gjøre nesten nøyaktig samme underarrangement og legge den til SpawnNewBlocks funksjon.

Sub-Event: Tilstand: System> Sammenlign to verdier Første verdi = loopindex ("X") Sammenligning Andre verdi: 7 Handling: System> Angi verdi Instansvariabel = CheckNewestRow Value = 1

SpawnNewBlocks skal nå se slik ut:

Denne underarrangementet gjør det samme som det forrige, bortsett fra at det aktiverer den andre hendelsen vi opprettet. Hvis du kjører spillet på dette punktet, bør du se at når du starter spillet, er det ikke lenger noen kampene som oppstår automatisk.


Konklusjon

I denne opplæringen gjorde vi ikke for mange endringer i spillet, men de vi gjorde var svært viktige.

På dette punktet synes jeg det er best for oss å stoppe for nå og lagre de to siste spillelementene for neste opplæring, hvor vi skal dekke kjeder / kombinasjoner og Game Over-skjermbildet. Dette blir den siste delen av serien, så jeg vil også snakke om noen spillmekanikk vi vil ikke dekke i disse opplæringsprogrammene, og gi deg noen råd om hvordan du kan lage disse systemene på egen hånd.

Hvis du vil ha en start på neste ukes innhold, kan du begynne å se hvordan du kan oppdage når skjermbildet Game Over skal dukke opp, basert på plasseringen eller høyden til noen av blokkene. Alternativt kan du begynne å tenke på hvordan du kan oppdage når spilleren lager en kjedereaksjon som forårsaker at flere enn en gruppe blir dannet.

Uansett hva du gjør, håper jeg å se deg tilbake her neste uke for den siste delen av serien.