Bygg et grid-basert puslespill som minesveiper i enhet vinnende

I den siste delen av denne serien legger vi slutt på våre nettbaserte Unity-puslespill, og gjør det mulig å spille. Ved slutten av denne delen vil spilleren kunne vinne eller miste spillet.

Nå som du har fullført de tidligere opplæringsprogrammene, kan vårt spill lage et felt av fliser, og tilordne miner tilfeldigvis til dem. Vi har også en fin lyseffekt når spilleren svinger over en flis med musen, og det er mulig å plassere og fjerne flagg.

Internt vet hver flis også om sine nabobilder, og kan allerede beregne hvor mange gruver i nærheten.

Avdekke fliser

Vi har allerede lagt til muligheten til å plassere flagg med et høyreklikk. Nå, la oss legge til evnen til å avdekke fliser med et venstre klikk.

I Onmouseover () funksjon, der vi har klikkgenkjenningskoden, må vi gjenkjenne et venstre klikk. Tilpass funksjonen slik at den ser slik ut:

funksjon OnMouseOver () if (state == "idle") renderer.material = materialLightup; hvis (Input.GetMouseButtonDown (0)) UncoverTile (); hvis (Input.GetMouseButtonDown (1)) SetFlag ();  annet hvis (tilstand == "flagget") renderer.material = materialLightup; hvis (Input.GetMouseButtonDown (1)) SetFlag (); 

Når du trykker på venstre museknapp, vil UncoverTile () funksjonen vil bli kalt. Pass på at du oppretter denne funksjonen, slik at dette ikke vil føre til feil!

funksjon UncoverTile () if (! isMined) state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered;  ellers Explode (); 

For at dette skal fungere, må vi presentere et nytt materiale.

offentlig var materialet oppdaget: materiale;

Lag noe som har en annen farge enn de grunnleggende fliserne, så hvis de grunnleggende fliser er blå, kan du velge grønn for avdekket stat. Men ikke bruk rødt; vi trenger det senere for å vise at vi har utløst en gruve.

Når du ringer den funksjonen, skjer følgende: 

  • Først sjekker vi om flisen faktisk blir utvunnet. 
  • Hvis ikke, setter vi staten til avdekket, aktiver tekstvisningen som viser oss antall nærliggende miner, og sett materialet til avdekket materiale. 
  • Etterpå kan flisen ikke klikkes igjen, og vil heller ikke lyse opp igjen, noe som betyr at passiv tilbakemelding av fliser som reagerer på musepekeren, bare vil skje på fliser vi faktisk kan klikke på.

Før vi kan prøve dette ut, må vi sørge for at materialet ikke endres når musemarkøren utganger flisen. For dette tilpasser du OnMouseExit () fungere som slik:

funksjon OnMouseExit () hvis (state == "idle" || state == "flagget") renderer.material = materialIdle; 

På denne måten blir fargen bare slått tilbake hvis flisene ennå ikke er avdekket.

Prøv det! Du bør kunne avdekke fliser. Hvis en flis gis, vil det imidlertid ikke skje noe nå.

Å lage tomme fliser avdekker hverandre

Dette vil være litt vanskelig. I Minesweeper, når du avdekker en flis med Neigruver ved siden av, vil det avdekke alle fliser ved siden av det som ikke har noen gruver, og flisene ved siden av dem som ikke har gruver og så videre.

Vurder dette feltet:

Vi ser faktisk ikke tallene eller gruvene, bare vanlige fliser.

Når en flis med null nærliggende gruver er avdekket, alle fliser ved siden av den skal automatisk bli avdekket. Den avdekket flisen avslører alle naboer.

Disse nyoppdagede fliser vil da sjekke sine naboer også, og hvis det ikke er noen gruver, avdekke dem også.

Dette vil kruse gjennom feltet til vi når fliser som faktisk har gruver ved siden av dem, hvor det vil stoppe.

Dette skaper tomme områder vi kan se i Minesweeper.

For å gjøre dette arbeidet trenger vi to flere funksjoner, UncoverAdjacentTiles () og UncoverTileExternal ():

private funksjon AvdekkendeTiler () for var currentTile: Tile in adjacentTiles // avdekke alle tilstøtende noder med 0 tilstøtende gruver hvis (! currentTile.isMined && currentTile.state == "tomgang" && currentTile.adjacentMines == 0) currentTile .UncoverTile (); // avdekke alle tilstøtende noder med mer enn 1 tilgrensende mine, og stopp deretter avdekke annet hvis (! currentTile.isMined && currentTile.state == "idle" && currentTile.adjacentMines> 0) currentTile.UncoverTileExternal ();  offentlig funksjon UncoverTileExternal () state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered; 

Vi må også gjøre denne endringen til UncoverTile () funksjon:

funksjon UncoverTile () if (! isMined) state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered; hvis (tilstøtendeMines == 0) avdekkeAdjacentTiles (); 

Når vi avdekker en flis, og det er ingen gruver ved siden av det, kaller vi UncoverAdjacentTiles () funksjon. Dette kontrollerer deretter hver naboland for å se om den har gruver eller ikke. også. Hvis det ikke er noe, avslører det også denne flisen, og starter en annen runde med kontroll. Hvis det er gruver i nærheten, oppdager det bare flisen den er for tiden på.

Nå, prøv det ut. For å få god sjanse for at et tomt felt vises, opprett et ganske stort felt med noen få miner - si 81 fliser, med ni fliser per rad og totalt 10 min.

Du kan faktisk nå spille dette som et spill, bortsett fra at du ikke kan utløse miner ennå. Vi legger til denne funksjonen neste.

Utløsende miner

Når vi avdekker en flis som blir malt, stopper spillet og spilleren taper. I tillegg blir alle andre gruvefliser synlige. For at dette skal skje, trenger vi et mer materiale, for detonerte minefliser:

Offentlig var materialeDetonert: Materiale;

Jeg foreslår at du bruker noe rødt for dette.

Også, vi må legge til to funksjoner for å håndtere eksploderer alle gruvene:

funksjon Explode () state = "detonated"; renderer.material = materialDetonated; for (var currentTile: Tile in Grid.tilesMined) currentTile.ExplodeExternal ();  funksjonen ExplodeExternal () state = "detonated"; renderer.material = materialDetonated; 

Vi utløser disse metodene i UncoverTile () funksjon:

funksjon UncoverTile () if (! isMined) state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered; hvis (tilstøtendeMines == 0) avdekkeAdjacentTiles ();  ellers Explode (); 

Hvis en flis gis, eksploderer flisen. De Eksplodere() funksjon sender deretter en "eksplodere" kommando til alle andre fliser med gruver, avslørende dem alle.

Vinner spillet

Spillet er vunnet når alle fliser med miner har blitt flagget riktig. På dette punktet er alle fliser som ikke er avdekket, avdekket. Så hvordan sporer vi det?

La oss begynne med å legge til en stat variabel til Nett klassen, slik at vi kan spore hvilken del av spillet vi er i øyeblikket (fortsatt spiller, tapt eller vant).

statisk var tilstand: String = "inGame";

Mens vi er i det, kan vi også begynne å legge til en enkel GUI, slik at vi kan vise nødvendig informasjon på skjermen. Enhet kommer med sitt eget GUI-system som vi skal bruke til dette.

funksjon OnGUI () GUI.Box (Rect (10,10,100,50), tilstand); 

Dette vil vise oss hvilken stat vi er i. Vi ringer disse statene i spill, spillet er slutt, og gameWon.

Vi kan også legge til sjekker til flisene, for å sikre at vi kun kan samhandle med fliser mens den nåværende spilltilstanden er i spill.

I Onmouseover () og OnMouseExit Funksjoner, flytt all eksisterende kode til en hvis blokk som sjekker om Grid.state er for øyeblikket i spill, som så:

funksjon OnMouseOver () if (Grid.state == "inGame") if (state == "idle") renderer.material = materialLightup; hvis (Input.GetMouseButtonDown (0)) UncoverTile (); hvis (Input.GetMouseButtonDown (1)) SetFlag ();  annet hvis (tilstand == "flagget") renderer.material = materialLightup; hvis (Input.GetMouseButtonDown (1)) SetFlag ();  funksjon OnMouseExit () hvis (Grid.state == "inGame") hvis (state == "idle" || state == "flagget") renderer.material = materialIdle; 

Det er faktisk to måter å sjekke om spillet har blitt vunnet: vi kan telle hvor mange gruver som er merket riktig, eller vi kan sjekke om alle fliser som ikke er gruver har blitt avdekket. For det trenger vi følgende variabler; legg dem til Nett klasse:

statisk var minesMarkedCorrectly: int = 0; statiske var fliser oppdaget: int = 0; statiske varminerRemaining: int = 0;

Ikke glem å sette minesRemainingi Start() funksjon til numberOfMines, og de andre variablene til 0. De Start() funksjonen skal nå se slik ut:

funksjon Start () CreateTiles (); minesRemaining = numberOfMines; minesMarkedCorrectly = 0; fliser oppdaget = 0; state = "inGame"; 

Den siste linjen setter staten for spillet. (Dette vil være viktig når vi ønsker å introdusere en "restart" -funksjon senere.)

Vi sjekker da etter våre spill i forhold til spillet Oppdater() funksjon:

Funksjon Oppdatering () if (state == "inGame") if ((minesRemaining == 0 && minesMarkedCorrectly == numberOfMines) || (fliser uttegnet == numberOfTiles - numberOfMines)) FinishGame (); 

Vi avslutter spillet ved å sette staten til gameWon, avdekker alle gjenværende fliser og flagger alle gjenværende gruver:

funksjon FinishGame () state = "gameWon"; // oppdager gjenværende felt hvis alle noder er plassert for (var currentTile: Tile in tilesAll) hvis (currentTile.state == "idle" &&! currentTile.isMined) currentTile.UncoverTileExternal (); // markerer gjenværende miner hvis alle noder unntatt gruvene har blitt avdekket for (var currentTile: Tile in Grid.tilesMined) hvis (currentTile.state! = "flaggert") currentTile.SetFlag (); 

For at alt dette skal fungere, må vi øke variablene som sporer vår fremgang på de rette stedene. Tilpass UncoverTile () fungere for å gjøre det:

funksjon UncoverTile () if (! isMined) state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered; Grid.tilesUcovered + = 1; hvis (tilstøtendeMines == 0) avdekkeAdjacentTiles ();  ellers Explode (); 

… samt UncoverTileExternal () funksjon:

funksjon UncoverTileExternal () state = "uncovered"; displayText.renderer.enabled = true; renderer.material = materialUtcovered; Grid.tilesUcovered + = 1; 

Vi må også øke og redusere minesMarkedCorrectly og minesRemaining variabler avhengig av om et flagg er satt:

funksjon SetFlag () hvis (tilstand == "tomgang") state = "flagged"; displayFlag.renderer.enabled = true; Grid.minesRemaining - = 1; hvis (erMined) Grid.minesMarkedCorrectly + = 1;  annet hvis (tilstand == "flagget") state = "idle"; displayFlag.renderer.enabled = false; Grid.minesRemaining + = 1; hvis (erMined) Grid.minesMarkedCorrectly - = 1; 

Å miste spillet

På samme måte må vi gjøre det mulig å miste et spill. Vi oppnår dette via Eksplodere() fungere innenfor flisen. 

Bare legg denne linjen til Eksplodere() funksjon:

Grid.state = "gameOver";

Når denne linjen er kjørt, byttes spillets tilstand til spillet er slutt, og flisene kan ikke lenger samhandles med.

Legge til en mer funksjonell GUI

Vi brukte Unity GUI noen få skritt siden for å fortelle spilleren hvilken spillstat de er i. Nå vil vi utvide den til å vise noen faktiske meldinger.

Rammen for dette ser ut som følgende:

funksjonen OnGUI () if (state == "inGame")  annet hvis (state == "gameOver")  annet hvis (state == "gameWon") 

Avhengig av tilstanden, vises forskjellige meldinger i GUI. Hvis spillet går tapt eller vant, kan vi for eksempel vise meldinger som sier det:

funksjon OnGUI () if (state == "inGame")  annet hvis (state == "gameOver") GUI.Box (Rect (10,10,200,50), "du mister");  annet hvis (state == "gameWon") GUI.Box (Rect (10,10,200,50), "Du rocker!"); 

Vi kan også vise antall miner funnet hittil, eller legg til en knapp som laster opp nivået når spillet er over:

funksjon OnGUI () if (state == "inGame") GUI.Box (Rect (10,10,200,50), "Mineer igjen:" + minerRemaining);  annet hvis (state == "gameOver") GUI.Box (Rect (10,10,200,50), "du mister"); hvis (GUI.Button (Rect (10,70,200,50), "Restart")) Start på nytt ();  annet hvis (state == "gameWon") GUI.Box (Rect (10,10,200,50), "Du rocker!"); hvis (GUI.Button (Rect (10,70,200,50), "Restart")) Start på nytt ();  funksjon Restart () state = "loading"; Application.LoadLevel (Application.loadedLevel); 

Du kan prøve alt i denne siste bygningen!

Konklusjon

Det er det! Vi har laget et enkelt puslespill med Unity, som du kan bruke som grunnlag for å lage din egen. Jeg håper du har hatt glede av denne serien; Spør spørsmål du har i kommentarene!