Faceți un joc Match-3 în Construct 2 Block Movement

În partea anterioară a acestei serii am realizat câteva modificări minore, dar importante ale multor sisteme pe care le-am creat pentru jocul Match-3. Odată cu implementarea acestor îmbunătățiri, vom reveni pe drumul cel bun și vom implementa unul dintre ultimele două sisteme majore pentru joc: sistemul de mișcare bloc.

Acest tutorial vă va duce prin întreaga dezvoltare a sistemului care permite blocurilor să se ridice în partea de sus a ecranului și va acoperi, de asemenea, crearea tuturor sistemelor mai mici pe care va trebui să le implementăm pentru a susține sistemul de mișcare. În timp ce subiectele pe care le acoperim în acest tutorial nu sunt prea complexe, există multe de parcurs - deci hai să ajungem la ele.


Joc final Demo

Iată o demonstrație a jocului pe care lucrăm în această serie:




1. Mutarea blocurilor în sus

Înainte de a începe să ne mișcăm blocurile, trebuie să facem o mică schimbare în ceea ce privește evenimentele care declanșează Blocurile. Mergeți la Sistem> La începutul layoutului eveniment și schimba Y pentru bucla de a merge de la 0 la 3, în loc de 0 la 7 așa cum a făcut inițial.

Evenimentul ar trebui să arate astfel:


Motivul pentru care am făcut această schimbare este că ne dorim ca jocul să înceapă cu mai puține blocuri pe ecran, astfel încât să nu se termine la fel de repede când adăugăm un Game Over în următorul tutorial.

Apoi, vom crea o variabilă care va reprezenta viteza blocurilor:

Variabila globală: Name = CurrentSpeed ​​Type = Number Value = 0.2

Acum vom crea evenimentul care mută blocurile:

Eveniment: Stare: Sistem> Fiecare intervale de X secunde (secunde) = Acțiune curentă: Bloc> Deplasare la unghi unghi = -90 Distanță = 1

Evenimentul ar trebui să arate astfel:


Dacă executați jocul după adăugarea acestui eveniment, primul lucru pe care ar trebui să îl vedeți este că blocurile scad, datorită gravității pe care am implementat-o ​​într-un tutorial anterior. După aceea, Blocurile ar trebui să se ridice încet până când se află în poziția lor inițială și apoi să renunțe din nou. Acest lucru se va repeta infinit atâta timp cât nu faceți nimic pentru blocuri.

Acest lucru se întâmplă deoarece Blocurile se mișcă dincolo de punctul în care ar trebui să pătrundă gravitatea și descoperă că nu există blocuri sub ele, cauzându-le să cadă toți. În timp ce aceasta este o problemă, nu este prima pe care vreau să o analizez.


2. Fixarea schimbării

Pornește jocul și încearcă să faci o schimbare de orice fel. Când faceți acest lucru, ar trebui să observați că blocurile încep să se blocheze în spatele celuilalt, blocându-se în poziții care nu sunt aliniate la grilaj și pur și simplu în general greșite. Există două motive pentru această problemă.

Prima problemă este că, deși ne mișcăm singuri Blocurile, nu ne mișcăm LeftBlock, RightBlock, TopBlock, și BottomBlock obiecte cu ele, ceea ce înseamnă că blocurile pe care le utilizați pentru a detecta swap-urile nu se mișcă cu grila de bloc - ele stau doar în poziția în care sunt setate la prima preluare a unui bloc.

Deci, atunci când încercați să faceți o schimbare, blocurile se scot din loc, deoarece blocurile de detectare a swap-urilor nu s-au adaptat la grilă. (Acesta este și motivul pentru cea de-a doua problemă pe care o avem, și anume că nu modificăm pozițiile pe care le-am stocat în BlockPositions array fie.)

GIF de mai jos demonstrează această problemă:


După cum puteți vedea în GIF, blocurile de detectare a swap-urilor nu se mișcă, chiar dacă blocurile sunt ele însele.

Pentru a rezolva aceste două probleme, vom adăuga încă câteva acțiuni la evenimentul pe care tocmai l-am creat:

Acțiune: BottomBlock> Deplasare la unghi Angle = -90 Distanță = 1 Acțiune: LeftBlock> Deplasare la unghi Angle = -90 Distanță = 1 Acțiune: Blocare dreapta> Deplasare la unghi Angle = -90 Distanță = 1 Acțiune: TopBlock> = -90 Distanță = 1 Acțiune: BlockPositions> Set la XY X = 0 Y = 1 Valoare = BlockPositions.At (0,1) - 1 Acțiune: BlockPositions> Setat la XY X = 1 Y = 1,1) -1

Evenimentul ar trebui să arate astfel:


Primele patru acțiuni pe care tocmai le-am adăugat ajustează pozițiile LeftBlock, TopBlock, RightBlock, și BottomBlock astfel încât să rămână în linie cu grila de bloc. Cele două două evenimente ajustează valorile Y pe care le-am stocat în BlockPositions astfel încât acestea să rămână în linie cu grila de bloc.

Dacă încercați din nou jocul în acest moment, schimbarea ar trebui să fie în mare parte fixată.

În acest moment, este încă o problemă cu care trebuie să ne ocupăm pentru a face schimbul corect de muncă. Rulați jocul și încercați să efectuați o schimbare descendentă cu oricare dintre blocurile din rândul de jos, în timp ce acel rând este parțial sub aria inferioară a câmpului de joc:

Faceți schimbul în timp ce blocurile se află în spatele marginii, ca cele evidențiate în imaginea de mai sus.

Dacă ați făcut acest lucru corect, ar trebui să vedeți că nu sa întâmplat nimic și că blocurile nu au fost schimbate. Dacă ați așteptat prea mult, blocurile s-ar fi putut schimba deoarece s-au mutat din nou deasupra graniței câmpului de joc, așa că, dacă acest lucru sa întâmplat, încercați din nou odată ce acestea cad și ar trebui să vedeți că această problemă apare.

Această problemă este destul de simplă de rezolvat și de înțeles. Dacă te uiți la codul pentru swap-urile descendente, ar trebui să găsești Evenimentul pe care l-am adăugat în tutorialul anterior care împiedică playerul să facă swap-uri descendente care fac Blocul să coboare din partea de jos a câmpului de joc. Deoarece această declarație împiedică playerul să facă swap-uri în jos atunci când BottomBlock obiectul este mai mic decât poziția Y inițială a blocului, împiedică blocurile să fie schimbate odată ce au căzut și vă permite doar să faceți din nou swap-uri odată ce au trecut din nou poziția inițială.

Pentru a repara această afirmație vom face o mică schimbare a condiției:

Stare: BottomBlock> Comparați Y Comparison = Mai mic sau egal Y co-ordonat = SPAWNY + ((Block.Width + 2) / 2)

Starea ar trebui să arate astfel:


Această modificare înseamnă că o schimbare descendentă poate apărea numai în timp ce BottomBlock obiectul este cel mult o jumătate de bloc sub poziția Y pe care blocurile pornesc. De asemenea, aceasta înseamnă că, odată ce începem să reproducem noi rânduri de blocuri și le împingem pe ecran de jos, aceste blocuri vor putea fi schimbate astfel, odată ce cel puțin jumătate din bloc este vizibil.

De asemenea, vom pune o restricție similară în toate evenimentele noastre de schimbare pentru a ne asigura că toate acestea devin utilizabile în același timp și că un bloc nu poate fi schimbat deloc până când cel puțin jumătate din acesta este vizibil. Din nou, acest lucru va ajuta, de asemenea, atunci când vom integra sistemul care produce nivele noi de blocuri. Pentru a face acest lucru, vom adăuga o nouă condiție fiecăruia dintre celelalte trei evenimente de swap.

Condițiile pe care le adăugăm vor fi exact aceleași cu cele pe care tocmai le-am modificat BottomBlock eveniment, cu excepția faptului că vor face referire la TopBlock, RightBlock, și LeftBlock obiecte în loc de BottomBlock obiect, în funcție de evenimentul în care se află.

Noua condiție pentru TopBlock Evenimentul ar trebui să fie:

Stare: TopBlock> Comparație Y Comparație = Mai puțin sau egal Y co-ordonat = SPAWNY + ((Block.Width + 2) / 2)

Noua condiție pentru LeftBlock Evenimentul ar trebui să fie:

Stare: LeftBlock> Comparație Y Comparison = Mai mic sau egal Y co-ordonat = SPAWNY + ((Block.Width + 2) / 2)

Noua condiție pentru RightBlock Evenimentul ar trebui să fie:

Stare: Blocare dreapta> Comparație Y Comparație = Mai puțin sau egal Y co-ordonat = SPAWNY + ((Bloc. Lățime + 2) / 2)

Întregul tău Pe drop DragDrop Evenimentul ar trebui să arate astfel:


Cu aceste noi condiții, ne-am fixat mecanica de schimbare și am început pregătirea sistemelor existente pentru următorul sistem pe care îl adăugăm: cel care va da naștere unor noi rânduri de blocuri.


3. Cresterea mai multor blocuri

Acum, când avem blocurile care se mișcă într-o rată constantă, trebuie să facem ca noile rânduri de blocuri să se dezvolte la momentul potrivit și să permită jucătorului să continue să joace atâta timp cât vor. Vom folosi o funcție pentru a da naștere noilor rânduri de blocuri și vom folosi un eveniment care detectează când blocurile sunt în linie cu SPAWNY pentru a declanșa această funcție.

Deci, mai întâi, să facem funcția în sine.

Eveniment: Stare: Funcție> Funcția On Funcția Name = "SpawnNewBlocks" Stare: System> Pentru Nume = "X" "X")) * (Block.Width + 2) Y = SPAWNY + (Block.Width + 2) Acțiune: Bloc> Setare instanță Variabila = la Variable = NumBlocks Valoare = 1

Noul dvs. eveniment ar trebui să arate astfel:


Când este folosit, această funcție va crea un rând de blocuri sub rândul de jos al blocurilor din câmpul de joc. Așa cum se întâmplă acum, totuși, nu folosim această funcție în niciun moment, deci facem evenimentul care face asta:

Eveniment: Stare: Sistem> La fiecare X secunde Interval (secunde) = CurrentSpeed ​​Stare: Bloc> Comparare Comparație Y = Egal cu Y = SPAWNY Stare: Inversare: Blocare>

Noul dvs. eveniment ar trebui să arate astfel:


Evenimentul pe care tocmai l-am creat verifică poziția Y a blocurilor de fiecare dată când sunt mutate. Dacă găsește blocuri care sunt în linie cu SPAWNY, declanșează SpawnNewBlocks () funcționează așa cum am discutat mai devreme. De asemenea, verifică pentru a se asigura că blocul pe care îl găsește nu este cel care este tras de către player.

Dacă încercați jocul în acest moment, va funcționa, dar ar trebui să observați o problemă ciudată. În momentul în care începeți jocul, blocurile dvs. vor cădea ca și cum nu ar exista blocuri sub ele, dar după acel punct totul funcționează perfect și se introduc noi blocuri oricând sunt necesare.

Acest lucru se întâmplă deoarece, atunci când jocul pornește primul, procesează codul de gravitație inainte de codul care generează noi rânduri de blocuri. Pentru a repara acest lucru, vom face o mică ajustare a codului care declanșează grupul inițial de blocuri, astfel încât acestea să fie create sub punctul în care ar fi nevoie de un nou rând. Acest lucru îi permite să evite imediat rularea codului de gravitate și îi permite să creeze noul rând de blocuri odată ce blocurile existente se află în poziția corectă.

Mergeți la evenimentul care generează grupul inițial de blocuri și modificați acțiunea care creează efectiv blocul. Modificați acțiunea la aceasta:

Acțiune: Sistem> Creare obiect Object = Blocare strat = 1 X = SPAWNX + (loopIndex ("X")) * (Block.Width + 2) Y = SPAWNY - 2) + 5

Evenimentul ar trebui să arate astfel:


Această modificare înseamnă că blocurile vor da naștere la cinci pixeli de mai jos SPAWNY. Acest lucru înseamnă că blocurile vor trebui să treacă de cinci ori înainte de începerea unui nou rând și ne vor rezolva problema.


4. Un pic de animație

În acest moment, blocurile noastre se mișcă și avem noi rânduri create. În plus, rețineți că mai devreme am împiedicat jucătorul să folosească orice bloc până când cel puțin jumătate din bloc este vizibil. În timp ce aceasta este o caracteristică bună, este posibil ca jucătorul să nu înțeleagă de ce un bloc nu poate fi folosit imediat când devine vizibil, chiar dacă nu o mare parte din acesta este vizibil în acel moment.

Din cauza acestei probleme de UI potențiale, vom face ca fiecare bloc să utilizeze sprite-ul de blocuri gri (la începutul cadrelor de animație ale blocului) atunci când este în această stare inutilizabilă. Acest lucru va face clar jucătorului atunci când un bloc devine utilizabil și ne va da șansa să folosim ultima noastră imagine bloc.

Puteți vedea un exemplu despre cum va arăta când Blocurile vor fi inactive la activ în GIF de mai jos:


Evenimentul pe care îl creăm va include și oa doua condiție care verifică dacă blocajul la care se uită nu este tras. Această condiție ne permite să ne asigurăm că atunci când jucătorul trage un bloc sub punctul în care blocurile devin utilizabile, acesta nu își va schimba imaginea astfel încât să fie gri și va rămâne culoarea pe care se presupune că este.

Pentru a face această lucrare de animație, trebuie mai întâi să adăugăm un nou eveniment:

Eveniment: Stare: Bloc> Comparare Y Comparison = Mai mare decât Y = SPAWNY + ((Block.Width + 2) / 2) Condiție: Invert: Block> Dragging Acțiune: Block> Set frame Frame number =

Noul eveniment ar trebui să arate astfel:


Acum ar trebui să puteți testa jocul și ar trebui să vedeți că blocurile utilizează imaginea gri atunci când acestea sunt sub punctul în care devin utilizabile.


5. Activarea și dezactivarea tragerii / iesirii

Dacă executați jocul acum, veți observa că, deși blocurile nu pot fi schimbate între ele atunci când sunt gri, blocurile gri pot fi totuși trase în jurul și manipulate. Acest lucru se datorează faptului că nu am dezactivat capabilitățile Drag / Drop ale blocului atunci când am împiedicat player-ul să facă schimb de ele.

Pentru a împiedica mutarea blocurilor gri, vom modifica Evenimentul pe care l-am creat în secțiunea anterioară. Mai întâi vom adăuga o nouă acțiune care va opri tragerea când blocul este sub punctul în care devine utilizabil.

Adăugați această acțiune la Evenimentul pe care l-am creat mai devreme:

Acțiune: Blocare (DragDrop)> Setare activat Stare = Dezactivat

Vom adăuga, de asemenea, o declarație Else pentru acest eveniment, care permite blocului să fie târât din nou, odată ce depășește punctul în care blocul devine utilizabil:

Eveniment: Stare: Altă acțiune: Bloc (DragDrop)> Setare stare activată = Activată

Cu ambele modificări, evenimentul ar trebui să arate astfel:


Dacă încercați jocul în acest moment, blocurile nu mai pot fi folosite atunci când sunt gri și ar trebui să funcționeze la fel cum au întotdeauna atunci când nu sunt.


6. Schimbări de viteză

Ultimul lucru pe care vreau să-l acordez în acest articol este sistemul care ne va permite să schimbăm viteza jocului în timp. În mod specific, acesta este sistemul care va face blocurile să se deplaseze mai repede, deoarece playerul elimină mai multe dintre ele.

Sistemul pe care îl vom crea este relativ simplu: de fiecare dată când jucătorul obține un număr de puncte, viteza jocului se va majora pe baza unui modificator pe care îl vom crea și a numărului de puncte pe care jucătorul trebuie să le obțină următoarea creștere de viteză se va modifica pe baza unui al doilea modificator.

Înainte de a putea începe efectiv realizarea Evenimentelor pentru acest sistem, vom crea câteva Variabile Globale care să se ocupe de noile caracteristici pentru noi:

Variabilă globală: SPEEDMOD Type = Număr Valoare inițială = 0.8 Constant = Da Variabila globală: PointsForSpeedUp Type = Număr Valoare inițială = 400 Constant = Nici o variabilă globală: valoare = 1,4 Constant = Da

Noile variabile ar trebui să arate astfel:


Acum, când avem variabilele în vigoare, voi explica ce are fiecare.

  • Speedmod este variabila pe care o vom multiplica viteza prin modificarea ei ori de cate ori jucatorul ajunge la numarul de puncte de care au nevoie pentru a determina o crestere a vitezei.
  • PointsForSpeedUp este numărul de puncte pe care trebuie să le atingă următoarea viteză.
  • PointsBetweenSpeedUps reprezintă cât de mult PointsForSpeedUp variabila va crește atunci când Player-ul primește o viteză în sus, să-l ajusteze astfel încât următoarea accelerare să ia și mai multe puncte. Chiar acum este de 400, cum ar fi PointsForSpeedUp, dar când jucătorul obține o accelerare, va fi înmulțit cu POINTSFORSPEEDUPMOD înainte de a fi adăugat la PointsForSpeedUp.
  • In cele din urma, POINTSFORSPEEDUPMOD este variabila pe care o vom folosi pentru a modifica numărul de puncte pe care trebuie să le obțină jucătorul pentru a-și mări viteza altceva decât cel pe care l-au obținut cel mai recent.

Împreună cu configurarea variabilelor, trebuie să creăm și un nou obiect sprite, care va acționa ca alertă pentru jucător atunci când crește viteza.

Mergi la Aspectul 1 și urmați acești pași pentru a crea noul sprite:

  1. Introduceți un nou spiriduș obiect pe Aspectul 1.
  2. Cu editorul de animație, deschideți imaginea SpeedIncImage.png.
    1. Seteaza Nume la SpeedIncreaseIndicator.
    2. Seteaza Strat la Câmp de joc.
    3. Seteaza Poziţie la 188, 329.
    4. A stabilit Vizibilitate inițială la Invizibil.
      1. Adauga o Decolorare Comportamentul la Sprite.
      2. A stabilit Activat la pornire la Nu.
      3. Seteaza Eliminați timpul la 2.5.
      4. A stabilit Distruge la Nu.

Aspectul dvs. ar trebui să arate astfel:


Acum vom crea evenimentul care schimbă viteza:

Eveniment: Stare: Funcție> Funcția On Funcția Name = "CheckForSpeedUp" Stare: Sistem> Comparație variabilă Variable = Comparație scor = Valoare egală sau egală ValueForSpeedUp Acțiune: SpeedIncreaseIndicator> Set vizibil Vizibilitate = Acțiune vizibilă: SpeedIncreaseIndicator> Variable = Valoare curentă rapidă = Actuală viteză * SPEEDMOD Sistem de acțiune> Valoare setată Variable = Puncte între valoarea de viteză rapidă = Puncte între viteza maximă * POINTSFORSPEEDUPMOD Acțiune: Sistem> Adăugare la Variable = PointsForSpeedUp Value = PointsBetweenSpeedUp

Evenimentul dvs. ar trebui să arate astfel:


Când această funcție este apelată, ea verifică dacă jucătorul a marcat suficiente puncte pentru a justifica o creștere a vitezei. Dacă au, atunci:

  • acesta activează sprite-ul care îi spune jucătorului viteza mărită făcând-o vizibilă și pornind Fade
  • crește viteza prin înmulțirea cu modificatorul
  • determină numărul de puncte necesare înainte de accelerarea următoare și
  • adaugă acea valoare la numărul total de puncte pe care playerul va trebui să le aibă înainte ca viteza să crească din nou.

Cu această funcție completă, trebuie să ne asigurăm că este chemată. Mergeți la GivePoints () și adăugați această acțiune la sfârșitul evenimentului principal și al sub-evenimentului:

Acțiune: Funcție> Funcție apel Nume = "CheckForSpeedUp"

GivePoints () funcția ar trebui să pară acum:


Cu acest eveniment complet trebuie să puteți testa jocul și să vedeți sistemul de accelerare în acțiune.

Bacsis: Pe măsură ce am jucat mai mult, am constatat că aceste valori s-au simțit puțin mai puțin, așadar vă sugerăm să vă petreceți ceva timp pentru a experimenta sistemul și pentru a găsi valorile cu care vă simțiți cel mai bine.


Concluzie

Am abordat o mulțime de subiecte în acest articol, dar tot ceea ce ne-am ocupat a fost în mod direct sau indirect legat de faptul că sistemul de mișcare a funcționat așa cum vrem. În timp ce a durat ceva timp și ne-a cerut să facem mai multe sisteme decât am fi anticipat la început, câștigul a meritat și am ajuns la un sistem foarte puternic în cele din urmă.

Din cauza cât de mult am acoperit deja, cred că este un loc bun pentru a încheia acest articol. Următorul articol ar trebui să fie ultimul tutorial din această serie și vom acoperi o mulțime de subiecte mai mici în cadrul acestuia, dar cel mai mare lucru pe care îl acoperim este cu siguranță eliminarea meciurilor pre-făcute.

Dacă doriți să începeți să încercați să aflați cum le vom elimina, aruncați o privire asupra modului în care detectăm potrivirile pentru început. Sistemul pe care îl creăm va fi foarte similar cu sistemul respectiv, cu excepția faptului că va folosi meciurile pe care le găsește într-un mod diferit. Începe să te gândești la asta și să vezi ce poți să vii și te voi vedea aici data viitoare pentru ultimul tutorial major din serie.