Så langt har denne serien dekket grunnlaget for å sette opp et Match-3-spill, og implementere de første spillelementene som blokkbytte. I denne opplæringen skal vi bygge videre på alt dette, og begynne å oppdage når spilleren har laget en kamp.
Her er en demonstrasjon av spillet vi jobber med i denne serien:
For nå skal vi bare implementere en grunnleggende versjon av det matchende systemet, med fokus på å finne når kampene eksisterer og ødelegge matchede blokker. I senere artikler vil vi fortsette å utvikle og fremme systemet.
Tips: Du bør lese inn hvordan en rekursiv funksjon fungerer, hvis du ikke allerede vet det; I hovedsak er det en funksjon som kaller seg. Rekursive funksjoner kan fungere på samme måte som sløyfer, men siden de også kan ta inn og returnere variabler, har de mange flere bruksområder enn sløyfer gjør.
Som med den forrige opplæringen vil jeg først diskutere hvordan systemet skal fungere, og deretter prøve å bygge det.
Blokkere
gjenstand. Blokkere
, det vil passere farge og posisjon av blokken den ser på i en rekursiv funksjon som vil se på den horisontale eller vertikale naboen, og avgjøre om de er i samme farge. matchet
med IsMatched
instansvariabel vi laget i en av de foregående opplæringsprogrammene; ellers gjør det ingenting. Først trenger vi et arrangement som kan lukte gjennom hver Blokkere
. Måten jeg bygde systemet på, det iterates faktisk gjennom blokkene to ganger: en gang for å sjekke om vertikale kamper, og en gang for å sjekke om horisontale kamper. Avhengig av hvilken sjekk det gjør, vil det bruke en annen funksjon til å faktisk se etter kampen.
Det aller første vi må gjøre er å lage en Global variabel for å holde oversikt over hvor mange matchende blokker vi har funnet i en gitt iterasjon:
Global Variable Name: "NumMatchesFound" Type = Nummerverdi = 0
La oss nå lage Begivenhet som vil iterere gjennom blokkene:
Hendelse: Funksjon> På funksjon Navn: "FindMatches" Sub-Event: System> For hvert objekt: Block Action: System> Angi verdi NumMatchesFound = 1 Handling: Funksjon> Anropsfunksjon Navn: "CheckMatchesX" Parameter 0: Block.X Parameter 1 : Block.Y Parameter 2: Block.Color Sub-Event: System> Sammenlign Variable NumMatchesFound> = 3 Handling: Blokker> Angi Boolean IsMatched = Ekte delhendelse: System> For hvert objekt: Blokker Handling: System> Angi verdi NumMatchesFound = 1 Funksjon: Funksjon> Anropsfunksjon Navn: "CheckMatchesY" Parameter 0: Block.X Parameter 1: Block.Y Parameter 2: Block.Color Sub-Event: System> Sammenlign Variable NumMatchesFound> = 3 Handling: Blokk> Angi Boolean IsMatched = True Sub-Event: Block> Er Boolean instans variabel satt System> Vent Second> 0.1 Block> Destroy
Koden din skal se slik ut:
I dette tilfelle vierer gjennom hver blokk og sender dem inn CheckMatchesX
eller CheckMatchesY
, funksjonene som vil sjekke for å se om naboblokken er en kamp.
For å sende blokken inn i funksjonen, sender vi funksjonene tre forskjellige parametere:
Etter hver blokk er sendt inn i en av funksjonene og funksjonen er ferdig, kontrollerer den NumMatchesFound
for å se om det fant tre eller flere matchende blokker, og merker deretter blokkene som matchet
hvis det gjorde det.
Til slutt, hver blokk som er merket som værende matchet
blir ødelagt etter .1 sekunder går. Dette vente
erklæringen er der for å tillate spillet å bytte bilder for blokkene til bildet som indikerer at de er matchet, og å gi spilleren et øyeblikk til å legge merke til denne endringen.
(Mens du kan fjerne vente
uttalelse uten å påvirke spillingen negativt, gjør det lettere for spilleren å forstå, og bremser spillet akkurat slik at spilleren lett kan holde rede på hva som skjer.)
Neste må vi lage CheckMatchesX
og CheckMatchesY
funksjoner. Disse funksjonene fungerer på samme måte som iteratorene ovenfor, idet det vil være en versjon for å sjekke horisontale kamper, CheckMatchesX
, og en for vertikale kamper, CheckMatchesY
.
La oss først bygge horisontal sjekkfunksjonen:
Hendelse: Funksjon> På funksjon Navn: "CheckMatchesX" Sub-Event: Tilstand: Blokk> Sammenlign XX = Funksjon.Param (0) + (Blokk.Width + 2) Tilstand: Blokk> Sammenlign YY = Function.Param (1) Tilstand : Blokk> Sammenlign instansvariabel Farge = Funksjon.Param (2) Handling: System> Legg til Variabel = NumBlocks Verdi = 1 Handling: Funksjon> Anropsfunksjon Navn: "CheckMatchesX" Parameter 0: Funksjon.Param (0) + (Blokk. Bredde + 2) Parameter 1: Funksjon.Param (1) Parameter 2: Funksjon.Param (2) Underhendelse: System> Sammenlign Variabel NumMatchesFound> = 3 Handling: Blokk> Angi Boolean IsMatched = True
Koden din skal se slik ut:
Så hva gjør denne funksjonen?
NumMatchesFound
av en, og sender den nylig funnet Blokken inn i funksjonen akkurat som den gjorde for originalen.La oss nå lage en annen versjon av denne funksjonen som vil gjøre det samme for vertikale kamper. Dette kommer til å bli vår CheckMatchesY
funksjon. Du kan enten kopiere den opprinnelige funksjonen og foreta de nødvendige endringene, eller bare bygge den på nytt fra begynnelsen. i begge tilfeller, her er hvordan din funksjon skal se når den er ferdig:
Hendelse: Funksjon> På funksjon Navn: "CheckMatchesY" Sub-Event: Tilstand: Blokk> Sammenlign XX = Funksjon.Param (0) Tilstand: Blokk> Sammenlign YY = Function.Param (1) + (Block.Width + 2) Tilstand : Blokk> Sammenlign instansvariabel Farge = Funksjon.Param (2) Handling: System> Legg til Variabel = NumBlocks Verdi = 1 Handling: Funksjon> Anropsfunksjon Navn: "CheckMatchesY" Parameter 0: Funksjon.Param (0) Parameter 1: Funksjon Parameter 2: Funksjon.Param (2) Underhendelse: System> Sammenlign Variabel NumMatchesFound> = 3 Handling: Blokker> Angi Boolean IsMatched = True
Koden din skal se slik ut:
Til slutt må vi faktisk ringe til FindMatches
funksjon. Gå til SwapBlocks
funksjon og legg til en ny underhendelse til slutten av funksjonen:
Hendelse: Funksjon> Underhendelse: Handling: Funksjon> Anropsfunksjon Navn: "FindMatches"
Du vil legge merke til at denne underhendelsen faktisk ikke har noen forhold. Hvis du aldri har gjort en underarrangement som dette før, må du bare lage en underhendelse med noen tilstand i det hele tatt, siden det krever at du gir en tilstand når du gjør en underhendelse, og deretter slett tilstanden, men la den gå sub-arrangement. På denne måten sørger du for at underarrangementet alltid kjører.
Din SwapBlocks
hendelsen skal nå se slik ut:
Hvis du kjører spillet på dette punktet, vil du se at blokkene blir ødelagt når kampene oppstår. Du vil også legge merke til at noen kamper som er der når spillet begynner, ikke forsvinner før du gjør en bytte av noe slag. Dette skyldes at vi aldri ringer til FindMatches
fungere etter at vi har opprettet grensesnittet til blokker.
Årsaken til at vi ikke har lagt til denne koden er fordi i den endelige versjonen vil det være en annen funksjon som forhindrer at kampene blir automatisk generert som dette, så det er egentlig ingen grunn til å bekymre seg for dette problemet i det hele tatt. (Men vær så snill å ringe FindMatches
fungere tidligere, hvis du vil.)
På dette tidspunktet har vi et ganske sterkt matchende system, men problemet er at vår kode er overflødig. For tiden har vi to forskjellige funksjoner som ser etter om det er en matchende nabo, og den eneste forskjellen mellom dem er at man sjekker vertikalt, og den andre kontrollerer horisontalt.
Siden den frie versjonen av Construct 2 begrenser hvor mange Hendelser vi kan ha, er dette definitivt en sløsing. For å løse dette skal vi lage en ny versjon av funksjonen som kan gjøre begge kontrollene.
Hvis du ser på funksjonen, vil du se den eneste forskjellen mellom de to versjonene er den man legger til Block.Width + 2
til x-posisjonen til blokken, og den andre legger den til y-posisjonen til bocken. Så, hindringen vi må komme forbi for å gjøre dette til en enkelt funksjon, gir funksjonen en måte å legge til Block.Width + 2
til bare X
, eller bare Y
, uten bruker en Hvis
setning eller flere funksjoner, siden de krever flere hendelser som skal utføres.
Min løsning på dette er ikke veldig kompleks, men det blir lettere å forstå om vi kan se det komme sammen, så vi vil implementere det, og jeg vil forklare hvordan det fungerer når vi kan se alt i bruk.
CheckMatchesY
begivenhet.CheckMatchesX
hendelse til, rett og slett, CheckMatches
.CheckMatchesX
under FindMatches
begivenhet: CheckMatches
i stedet for CheckMatchesX
.Parameter 3
. 1
.Parameter 4.
0
.CheckMatchesY
under FindMatches
begivenhet: CheckMatches
i stedet for CheckMatchesY
.Parameter 3
. 0
.Parameter 4
. 1
.Som jeg vil forklare snart, vil disse ekstra parametrene fortelle CheckMatches
enten det er en horisontal kontroll eller en vertikal kontroll. Når vi sender inn 1
til Parameter 3
, og 0
til Parameter 4
, Det er en horisontal sjekk, og når vi sender inn 0
til Parameter 3
, og 1
til Parameter 4
, Det er en vertikal kontroll.
Gå nå tilbake til CheckMatches
funksjonen, og endre vilkårene og handlingene for å se slik ut:
Hendelse: Funksjon> På funksjon Navn: "CheckMatches" Sub-Event: Tilstand: Blokk> Sammenlign XX = Funksjon.Param (0) + ((Blokk.Width + 2) * Funksjon.Param (3)) Tilstand: Blokk> Sammenlign YY = Function.Param (1) + ((Block.Width + 2) * Function.Param (4)) Tilstand: Blokk> Sammenlign instansvariabel Farge = Funksjon.Param (2) Handling: Blokk> Angi boolsk IsMatched = True Action : Funksjon> Anropsfunksjon Navn: "CheckMatches" Parameter 0: Function.Param (0) + ((Block.Width + 2) * Function.Param (3)) Parameter 1: Funksjon.Param (1) + ((Blokk. Bredde + 2) * Funksjon.Param (4)) Parameter 2: Funksjon.Param (2) Parameter 3: Funksjon.Param (3) Parameter 4: Funksjon.Param (4) Underhendelse: System> Sammenlign Variabel NumMatchesFound> = 3 Handling: Blokk> Angi boolsk IsMatched = True
Dette er hva din FindMatches
og CheckMatches
koden skal nå se ut som:
Så, hva er denne nye versjonen av funksjonen som faktisk gjør?
Vel, når du ringer CheckMatches
Du sender nå to parametere, og heller enn å legge til Block.Width + 2
til enten x- eller y-stillingen, legger den til (Block.Width + 2) * Function.Param (3)
til x-stillingen, og (Block.Width + 2) * Function.Param (4)
til y-posisjonen.
Siden en av de to parametrene vil alltid være 1
, og den andre vil alltid være 0
, Dette betyr at enten x- eller y-stillingen vil bli endret - aldri begge deler!
For eksempel, hvis vi passerer inn 1
til Parameter 3
, og 0
til Parameter 4
, da legger det til (Block.Width + 2) * 1
, som er rett og slett Block.Width + 2
, til x-stillingen, og (Block.Width + 2) * 0
, som er 0
, til y-posisjonen.
Her er et raskt eksempel for å vise hva jeg mener og hvordan det beregner posisjonen til blokken hvor den vil sjekke for kampen. La oss si at i dette eksemplet er den opprinnelige blokken hos (200, 200)
, og blokkene har en bredde på 40
. Så, hvis vi ønsker å få posisjonen til den nærliggende vertikale blokken, vil formlene trenge slik ut:
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
Hvis vi ønsket å få posisjonen til den nærliggende horisontale blokken, ville formlene virke slik:
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
Hvis du kjører spillet nå, bør du se at kampsystemet fungerer fortsatt som det opprinnelig gjorde, men fra vårt perspektiv er det faktisk et bedre system.
På dette tidspunktet er vår gjenkjenningsfunksjon fortsatt ufullstendig, men vi har allerede gjort mye i denne opplæringen allerede, og jeg synes det er viktig å la alt dette synke inn før vi legger til noe annet. Med det for øye, skal jeg avslutte denne artikkelen her. Sjekk ut demoen i sin nåværende form.
I neste artikkel vil vi legge til et poengsystem, vi vil forbedre matchende systemet, og vi vil legge til "tyngdekraft" slik at blokkene vil falle når blokker under dem blir eliminert.
Hvis du vil ha en start på neste artikkel, tar du litt tid til å vurdere hvordan du vil oppdage når det er tomt plass under en blokk. Prøv å se på Blokker> Overlapper ved forskyvning
Funksjon for inspirasjon!