Continuăm construirea gamei de puzzle-uri bazate pe rețea prin conectarea plăcilor unul cu celălalt, făcându-le să lumineze cu cursorul mouse-ului și adăugând capacitatea de a plasa steaguri.
În ultima parte a acestui tutorial, am creat un câmp de dale care formează baza pentru jocul nostru de puzzle. În această parte, o vom face să se poată juca. Acest tutorial urmează direct din ultima parte, așa că citiți-l înainte de a începe acest lucru.
Când mouse-ul este peste o țiglă, vrem să se aprindă. Aceasta este o caracteristică interesantă care oferă chiar și acțiuni simple (cum ar fi mutarea indicatorului mouse-ului) feedback instantaneu.
Noi folosim OnMouseover ()
pentru a realiza acest lucru. Se numește automat ori de câte ori cursorul mouse-ului se deplasează peste obiectul pe care este atașat codul. Adăugați aceste variabile la Ţiglă
script:
public var materialIdle: material; public var materialLightup: Material;
Apoi, atribuiți materialul de țiglă de bază materialIdle
slot. Avem de asemenea nevoie de a a lumina material, care ar trebui să aibă aceeași culoare, dar utilizează un shader diferit. În timp ce materialul de bază poate avea a difuz Shader ...
... materialul de lumină ar putea avea a speculară shader. Multe jocuri folosesc și un shader suplimentar pentru acest efect. Acestea nu vin cu Unitatea, dar dacă vă puteți da seama cum să obțineți una, puteți să o utilizați în schimb!
Nu uitați să alocați de fapt materialele Material sloturi pe prefab, astfel încât acestea să poată fi utilizate.
Apoi adăugați aceasta OnMouseover ()
funcția la Ţiglă
scenariu
funcția OnMouseOver () renderer.material = materialLightup;
Încearcă! Când mutați cursorul mouse-ului peste plăci, ar trebui să-și schimbe aspectul.
Ce ați fi observat este că plăcile își schimbă aspectul odată ce mouse-ul este peste ele, dar nu se schimbă înapoi. Pentru asta, trebuie să folosim OnMouseExit ()
funcţie:
funcția OnMouseExit () renderer.material = materialIdle;
Și voilá; acum avem plăci care se aprind și fac jocul mult mai interesant.
Pentru a avea gresie să comunice unul cu celălalt (pentru a afla câte mine sunt în apropiere), fiecare țiglă trebuie să cunoască plăcile vecine. O modalitate de a realiza acest lucru este utilizarea de ID-uri, pe care fiecare placă va fi atribuită.
Începeți prin adaptarea codului Tile pentru a include un ID-ul
variabil. De asemenea, adăugați o variabilă pentru a ține numărul de plăci pe rând, pe care le vom folosi în acest calcul:
public var ID: int; public var tilesPerRow: int;
Apoi, modificați comanda instanțiată în codul Grid pentru a arăta ca fragmentul următor. (Noua linie atribuie ID-uri plăcilor în momentul în care sunt create.)
var newTile = Instanțiate (tilePrefab, Vector3 (transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation); newTile.ID = tilesCreated; newTile.tilesPerRow = tilesPerRow;
Prima placă va primi ID-ul 0, următorului i se va atribui ID-ul 1, si asa mai departe. Puteți să le verificați făcând clic pe plăci în timpul executării și văzând numărul în care au fost atribuite.
Acum vrem ca fiecare piesă să cunoască plăcile vecine. Atunci când executăm o acțiune pe o țiglă (cum ar fi descoperirea ei), trebuie să luăm în considerare țiglele învecinate.
În cazul nostru, aceasta înseamnă numărarea minelor adiacente plăcii pe care tocmai am descoperit-o și, eventual, descoperirea altor plăci - dar vom ajunge la asta mai târziu.
Acest lucru poate fi, de asemenea, folosit pentru a verifica, de exemplu, dacă trei sau mai multe plăci se află unul lângă celălalt într-un joc Match-3.
Începeți prin adăugarea acestor variabile în scriptul Tile:
public var tileUpper: Placi; public var tileLower: Placi; public var tileLeft: țiglă; public var tileRight: țiglă; public var tileUpperRight: țiglă; public var tileUpperLeft: țiglă; public var tileLowerRight: țiglă; public var tileLowerLeft: țiglă;
Acestea vor ține toate plăcile vecine. Acestea sunt publice, astfel încât să putem verifica în timpul runtime că au fost atribuite corect.
Din moment ce fiecare placă are un ID, numărul de plăci care apar într-o coloană și accesul la matricea statică care are toate dalele salvate în Grilă
, putem calcula pozițiile plăcilor vecine după ce au fost create.
Această parte arată astfel:
tileUpper = Grid.tilesToate [ID + tilesPerRow]; tileLower = Grid.tilesToate [ID - tilesPerRow]; tileLeft = Grid.tilesAll [ID-1]; tileRight = Grid.tiles Toate [ID + 1]; tileUpperRight = Grid.tilesToate [ID + tilesPerRow + 1]; tileUpperLeft = Grid.tiles Toate [ID + tilesPerRow - 1]; tileLowerRight = Grid.tilesToate [ID - tilesPerRow + 1]; tileLowerLeft = Grid.tilesAll [ID - tilesPerRow - 1];
Cu ID-urile și numărul de plăci pe rând, putem calcula care sunt țiglele în apropiere. Să presupunem că piesa care face calculele are ID-ul 3
, și că există cinci plăci pe rând. Tigla de deasupra lui va avea ID-ul 8
(ID-ul plăcilor selectate plus numărul de plăci pe rând); țigla din dreapta va avea ID-ul 6
(ID-ul plăcilor selectate plus unul) și așa mai departe.
Din păcate, acest lucru nu este suficient. Codul verifică corect numerele, dar când le cere allTiles
pentru a returna plăcile, poate solicita numerele index care sunt în afara domeniului, producând o listă lungă de erori.
Pentru a rezolva acest lucru, trebuie să verificăm dacă indexul pe care îl solicităm din matrice este de fapt valabil. Cel mai eficient mod de a face acest lucru este unul nou inbounds ()
funcţie. Adăugați-o în Tiglă:
funcția privată inBounds (inputArray: Array, targetID: int): boolean if (targetID < 0 || targetID >= inputArray.length) return false; altceva returnează adevărat;
Acum trebuie să verificăm faptul că fiecare posibil țiglă vecină este în limitele matricei care deține toate plăcile, înainte de a încerca să o obținem din matrice:
dacă (inBounds (Grid.tilesAll, ID + tilesPerRow)) tileUpper = Grid.tilesToate [ID + tilesPerRow]; dacă (inBounds (Grid.tilesAll, ID - tilesPerRow)) tileLower = Grid.tilesAll [ID - tilesPerRow]; dacă (inBounds (Grid.tilesAll, ID-1) && ID% tilesPerRow! = 0) tileLeft = Grid.tilesAll [ID-1]; dacă (inBounds (Grid.tilesAll, ID + 1) și& (ID + 1)% tilesPerRow! = 0) tileRight = Grid.tilesAll [ID + 1]; dacă (inBounds (Grid.tilesAll, ID + tilesPerRow + 1) && (ID + 1)% tilesPerRow! = 0) tileUpperRight = Grid.tilesAll [ID + tilesPerRow + 1]; dacă (inBounds (Grid.tilesAll, ID + tilesPerRow - 1) && ID% tilesPerRow! = 0) tileUpperLeft = Grid.tilesToate [ID + tilesPerRow - 1]; dacă (inBounds (Grid.tilesAll, ID - tilesPerRow + 1) && (ID + 1)% tilesPerRow! = 0) tileLowerRight = Grid.tilesAll [ID - tilesPerRow + 1]; dacă (inBounds (Grid.tilesAll, ID - tilesPerRow - 1) && ID% tilesPerRow! = 0) tileLowerLeft = Grid.tilesAll [ID - tilesPerRow - 1];
Acest bloc de cod verifică toate posibilitățile. Verifică, de asemenea, dacă o țiglă se află la marginea câmpului. O țiglă de pe marginea dreaptă a grilajei, la urma urmei, nu are în realitate nici o piesă dreapta.
Încearcă! Verificați câteva dale și vedeți dacă ați recuperat corect toate plăcile vecine. Ar trebui să arate astfel:
Cum țiglă din această captură de ecran este o țiglă pe marginea dreaptă a câmpului, nu are vecini la dreapta, la dreapta sus sau la dreapta jos. Variabilele fără plăci atribuite sunt golite corect, iar un test arată că cele rămase au fost atribuite corect.
În cele din urmă, odată ce ne-am asigurat că funcționează, adăugăm toate plăcile vecine într-o matrice, astfel încât să le putem accesa toate dintr-o dată mai târziu. Trebuie să declarăm această matrice la început:
public var adjacentTiles: Array = array nou ();
Apoi puteți adapta fiecare linie a algoritmului creat mai sus pentru a introduce fiecare țiglă vecină în matricea respectivă sau adăugați acest bloc după aceea:
dacă (tileUpper) adiacenteTiles.Push (tileUpper); dacă (tileLower) adiacenteTiles.Push (tileLower); dacă (tileLeft) adiacenteTiles.Push (tileLeft); dacă (tileRight) adiacenteTiles.Push (tileRight); dacă (tileUpperRight) adiacenteTiles.Push (tileUpperRight); dacă (tileUpperLeft) adiacenteTiles.Push (tileUpperLeft); dacă (tileLowerRight) adiacenteTiles.Push (tileLowerRight); dacă (tileLowerLeft) adiacenteTiles.Push (tileLowerLeft);
După ce au fost create toate dalele, toate minele au fost atribuite și fiecare piesă a recuperat vecinii, atunci trebuie să verificăm dacă fiecare dintre aceste plăci vecine este minată sau nu.
Codul Grid alocă deja numărul specificat de mine pentru plăcile alese aleatoriu. Acum avem nevoie doar de fiecare piesă pentru a verifica vecinii săi. Adăugați acest cod la începutul Ţiglă
script, astfel încât să avem un loc pentru a stoca cantitatea de mine:
public var adjacentMines: int = 0;
Pentru a le număra, trecem prin matricea în care am adăugat anterior toate plăcile vecine și verificăm fiecare intrare pentru a vedea dacă este minată. Dacă da, vom mări valoarea adjacentMines
de 1.
funcția CountMines () adjacentMines = 0; pentru fiecare (var currentTile: Tile în adiacenteTiles) dacă (currentTile.isMined) adjacentMines + = 1; displayText.text = adâncimeMines.ToString (); în cazul în care (adjacentMines <= 0) displayText.text = "";
Această funcție stabilește, de asemenea, elementul text al plăcii pentru a afișa numărul de mine aflate în apropiere. Dacă nu există mine, nu se afișează nimic (mai degrabă decât 0).
Să adăugăm a stat
la fiecare placă. În acest fel, putem urmări starea în care se află în prezent-inactiv
, neacoperit
, sau fanionat
. În funcție de starea în care se află piesa, aceasta va reacționa diferit. Adăugați-o acum, pe măsură ce o vom folosi într-un moment.
public var state: String = "inactiv";
Vrem să putem marca piese ca fanionat. O piesă cu pavilion are un mic pavilion mic pe partea de sus a acesteia. Dacă faceți clic dreapta pe pavilion, va dispărea din nou. Dacă toate plăcile minate au fost marcate și nu există plăci incorecte cu pavilioane rămase, jocul este câștigat.
Începeți prin a crea un obiect de pavilion și adăugați-l la placă (veți găsi o plasă de pavilion în fișierele sursă).
De asemenea, avem nevoie de o variabilă pentru a accesa steagul. Adăugați acest cod:
public var displayFlag: GameObject;
Amintiți-vă să trageți steagul care face parte din țiglă pe displayFlag slot.
De asemenea, adăugați acest lucru la start()
funcția plăcii:
displayFlag.renderer.enabled = false; displayText.renderer.enabled = false;
Aceasta va dezactiva stegulețul și textul la început. Mai târziu, putem atunci Activati un pavilion, făcând din nou vizibil, punându-l efectiv acolo. Alternativ, dacă noi descoperi o țiglă, facem din nou textul vizibil.
Vom scrie o funcție care se ocupă atât de plasarea cât și de eliminarea steagurilor:
funcția SetFlag () if (state == "idle") state = "marcat"; displayFlag.renderer.enabled = true; altfel dacă (state == "marcat") state = "inactiv"; displayFlag.renderer.enabled = false;
Odată ce ați adăugat acest lucru, adăugați și codul pentru a gestiona un eveniment de clic. Pentru a face acest lucru, adaptați OnMouseover ()
funcția pe care trebuie deja să o verificăm pentru un click de mouse:
funcția OnMouseOver () if (state == "inactiv") renderer.material = materialLightup; dacă (Input.GetMouseButtonDown (1)) SetFlag (); altfel dacă (state == "marcat") renderer.material = materialLightup; dacă (Input.GetMouseButtonDown (1)) SetFlag ();
Aceasta va recunoaște un clic dreapta (buton 1
) și activați SetFlag ()
funcţie. Apoi va activa sau dezactiva steagul pe placa actuală. Încearcă!
Am extins jocul nostru de puzzle cu mai multe caracteristici vitale, l-am făcut vizibil mai interesant și am dat jucătorului posibilitatea de a afecta câmpul de joc.
Data viitoare vom adăuga descoperirea plăcilor, vom face o interfață simplă și vom transforma acest lucru într-un joc adecvat.