Gör ett match-3-spel i Construct 2 Chaining och Game Overs

Tiden har äntligen kommit: vi är nästan färdiga med vårt spel och är redo att genomföra den sista spelmekanikern. Denna artikel kommer att fokusera på att skapa ett kombinationssystem som ger spelaren fler poäng för att skapa kedjor som förstör flera grupper av block efter bara en byte.

Utöver det kommer vi att implementera förlustscenariot och lägga till en Game Over-skärm. Slutligen ska jag prata om saker du kan arbeta på i din egen tid för att förbättra och expandera spelet bortom vad vi har täckt. Så, utan vidare, låt oss komma igång ...


Final Game Demo

Här är en demonstration av spelet vi har arbetat för, och som vi kommer att ha byggt i slutet av den här delen av serien:




Hitta matchningar

Innan vi går vidare till huvudartikeln vill jag göra en liten förändring till när FindMatches kallas.

Under arbetet med den här artikeln upptäckte jag ett problem som du kan se i GIF nedan:

Som du kan se i denna första GIF, när ett block släpps bara ett blockavstånd för att försöka bilda en matchning med en grupp av block längst ner på hösten, fungerar det perfekt.

I denna andra GIF blir det emellertid klart att när ett block har tappat ett större avstånd i samma scenario, klarar det inte att upptäcka matchen tills vi utför en annan byte. Anledningen till detta är att spelet inte letar efter matcher ofta nog.

Just nu söker spelet bara efter matcher efter ett byte, men på grund av hur mycket tid det tar ett Block att falla detta avstånd, har matchdetektering redan slutat när Blocken träffar marken och matchen hittas inte förrän det påbörjas igen.

För att åtgärda detta ändras vi när vi utför en FindMatches kontrollera.

Gå först till SwapBlocks funktionen och ta bort den slutliga händelsen från funktionen så att den inte ringer FindMatches alls.

SwapBlocks ska se ut så här nu:

Vid denna tidpunkt finns det ingen händelseanrop FindMatches. Vi fixar det genom att lägga till en ny åtgärd till händelsen som upptäcker när matchningar är möjliga. Hitta den här händelsen och lägg till den här åtgärden till slutet av den andra händelsen:

Åtgärd: Funktion> Samtalsfunktion Namn = "FindMatches"

Din händelse ska nu se ut så här:

Ta också chansen att flytta båda MatchesPossible Händelser till slutet av spelkoden, om du inte redan har det. Om du gör det kommer du att försäkra dig om att de inte alls kallas för koden, vilket eliminerar förlagda matchningar.

Om du kör spelet nu borde du kunna utföra det scenario jag presenterade ovan utan problem.


kedja

Med den frågan fast, kommer vi att genomföra chaining system, vilket ger spelaren extra poäng för matcher som orsakas av förstörelsen av en annan match.

Du kan se ett exempel på den typ av situation som jag menar nedan:

I ovanstående scenario flyttar spelaren det gröna blocket och skapar en matchning. Därefter orsakar förstörelsen av de gröna blocken de blå blocken att falla och skapa ytterligare en matchmoment senare.

Jag vill ge spelarens bonuspoäng för att uppnå något som detta. Specifikt vill jag tillämpa en multiplikator på antalet poäng som spelaren får för varje match och multipliceraren ökar med varje på varandra följande matchning som görs.

Gör det till jobbet

För att systemet ska fungera ska vi ringa en ny variabel Kedja, och gör sedan några små ändringar av de befintliga funktionerna. Så först skapa en ny Global Variabel:

Global Variabel: Kedjetyp = Antal Initialt värde = 0

Din variabel ska se ut så här:

Denna variabel kommer att fungera som en multiplikator för punkterna att berätta hur länge en kedja har gått.

Gå nu till evenemanget som orsakar blocken att falla och ta bort Else Event som kallar FindMatches fungera.

Gå nu till FindMatches själv och hitta de platser där du gör FloatingPointsText objekt. Ändra inställda textuppsättningar så att de använder en ny formel:

Åtgärd: FloatingPointsText> Ange text Text = NumMatchesFound * 10 * Chain

Denna ändring gör att den flytande texten ändras på samma sätt som Punkterna själv så småningom kommer att göra.

Gå sedan till avsnittet av FindMatches var du ringer FindMatches igen i slutet av händelsen och radera detta funktionssamtal och vänteläge. Varför? Om vi ​​inte tog bort dessa, då FindMatches skulle bli kallade för många gånger och kedjorna skulle aldrig initieras korrekt.

(På grund av de förändringar som vi gjort tidigare i den här artikeln, FindMatches kommer att ringas när alla block är i rutnätet och ingen faller. Har flera områden där vi ringer FindMatches skulle bara orsaka att flera instanser av funktionen körs samtidigt, och kan förstöra punktsystemet.)

Slutligen kommer vi att göra en annan förändring till denna funktion. Gå till slutet av funktionen och lägg till den här åtgärden när du har ställt in PointsGiven till 0:

Åtgärd: System> Lägg till Variabel = "Kedja" Värde = 1

Nu, när spelet hittar matchningar, ger det spelarens poäng, förstör blocken, och ökar sedan kedjevärdet.

Den nya versionen av FindMatches ska se så här ut:

Gå sedan till GivePoints funktion och modifiera båda åtgärderna som ökar värdet på poängen så att de tar hänsyn till kedjevärdet:

Åtgärd: System> Lägg till Variabel = Poängvärde = 10 * Kedja

Med denna förändring, GivePoints ska nu se ut så här:

Återställa kedjan

Vi har implementerat den variabla kedjan som en multiplikator för de punkter som spelaren mottar (och antalet poäng som visas i de flytande textobjekten), men det finns fortfarande en sak vi behöver göra: vi måste lägga till ett uttalande som återställer värdet av kedjan så att det inte bara kommer att öka oändligt.

Vi kommer att lägga till detta uttalande till På DragDrop Start Händelse så att varje gång spelaren börjar dra ett nytt block betraktas det som en ny kedja. Den andra anledningen till att vi gör det här är att det förhindrar att kedjevärdet återställs för tidigt, vilket gör alla matcher i den senare delen av en kedja mindre värdefulla.

Gå till På DragDrop Start Händelse och lägg till den här åtgärden i listan Åtgärder:

Åtgärd: System> Ange värde Variabel = Kedjevärde = 1

Din händelse ska nu se ut så här:

Om du testar spelet vid denna tidpunkt bör du se att om du gör en kedja som den som jag visade i gif tidigare, får du 90 poäng i stället för 60 poäng.

Med det arbetet är kedjesystemet komplett och du borde kunna skapa så utarbetad en kedja som du vill utan problem.


Fixing Falling

Nästa sak jag vill täcka är ett problem jag har hittat med Block fallande systemet. Om du spenderar mycket tid på att spela vårt Match-3-spel i sitt nuvarande tillstånd har du kanske märkt ett problem där det kommer att bli ett block då och då, men det finns inget block under det.

Du kan se vad jag menar på bilden nedan:


Trots att det inte finns något block under det gula blocket har det fortfarande misslyckats att falla in i det tomma utrymmet. Det här är en sällsynt fråga, men om det inte hanteras kan det fortfarande störa någons poäng och förhindra att de tar emot en kedja de ställer in eller till och med förlorar dem när vi lägger till Game Over-funktionen.

Problemet kommer från variabeln BlockBeingMoved, som används av händelsen som bestämmer när block ska falla för att säkerställa att det inte finns några block som flyttas när det säger ett block att fylla i ett tomt utrymme. I vissa scenarier, när spelaren flyttar ett block, återställs denna variabel aldrig och blocken faller inte förrän ett annat block flyttas och det återställs korrekt. För att åtgärda detta kommer vi att lägga till ett par händelser som kommer att ställa in och återställa denna variabel korrekt, och vi tar bort de aktuella åtgärderna som ställer in variabeln, eftersom de inte fungerar korrekt.

Först, gå till OnDragDrop Start och På DragDrop Drop Händelser och ta bort alla åtgärder som handlar om BlockBeingMoved variabel från dessa händelser. Det bör finnas en åtgärd i varje händelse som måste raderas.

Gå sedan till händelsen som upptäcker när det finns ett tomt utrymme under ett block. Vi kommer att ändra villkoren för denna händelse. Kontrollera först att villkoret som kontrollerar om BlockBeingMoved är lika med 0 är i början. Lägg sedan till ett annat villkor i slutet av händelsen som kontrollerar att inga block ska flyttas.

Det här är det villkor du lägger till:

Skick: Omvänd: Block> Dra

Din händelse ska nu se ut så här:


Slutligen kommer vi att lägga till ytterligare två händelser i slutet av Event Sheet som kommer att hantera BlockBeingMoved variabel. Gå till slutet av din Event Sheet och lägg till dessa evenemang:

Händelse: Skick: Block> Släpper Åtgärd: System> Ställ in variabel Namn = BlockBeingMoved Value = 1
Händelse: Skick: System> Övrig åtgärd: System> Ställ in variabel Namn = BlockBeingMoved Value = 0

Dina nya händelser ska se ut så här:


Dessa händelser kommer att förändras effektivt BlockBeingMoved från 0 till 1 och från 1 till 0 när ett block flyttas eller är inte flyttas. Om du testar spelet på denna punkt borde du kunna spela så många gånger du vill utan att stöta på några problem med Block falling.


Spel över

Nu när vårt kedjesystem är på plats, lägger vi till förlustscenariot och en Game Over-skärm.

Det första vi behöver göra är att lägga till en ny layout som kommer att fungera som vår Game Over Screen:

  1. Högerklicka på knappen på höger sida av skärmen layouter mapp och välj Lägg till layout.
  2. Välj Lägg till händelseblad.
  3. Gå till den nya Layouten och skapa en ny BG Tile objekt.
    1. Välj bilden GameOverBGTile.png från BG bilder mapp i grafikpaketet du laddade ner under den första handledningen.
    2. Ställ in Placera till -6, -7.
    3. Ställ in Storlek till 613, 619.
  4. Skapa en ny Sprite objekt.
    1. Välj bilden GameOverText.png från grafikpaketet.
    2. Ställ in Placera till 303, 200.
  5. Skapa en ny Knapp objekt.
    1. Ställ in namn till RestartButton.
    2. Ställ in Placera till 262, 410.
    3. Ställ in Storlek till 100, 30.
    4. Ställ in Text till Omstart.

Nu när du har ställt in din Game Over-skärm, gå tillbaka till din ursprungliga Layout, Layout 1, och lägg till ett nytt objekt på skärmen:

  1. På Layout 1, skapa en ny Sprite objekt.
  2. Använd Målarfärgsburk verktyg för att måla denna sprite helt röd.
  3. Stäng animeringsredigeraren.
  4. Ställ in namn till GameOverArea.
  5. Ställ in Placera till 196, -30.
  6. Ställ in Storlek till 344, 150.
  7. Ställ in Opacitet till 0.

Du bör märka att denna sprite är i samma position och i samma storlek som den övre delen av spelfältet. Vi kommer att använda detta spriteobjekt för att upptäcka när spelaren har förlorat genom att upptäcka när ett block kolliderar med det. Gå till Event Sheet 1 så vi kan börja implementera detta.

Stoppar blocken på toppen

Innan vi börjar upptäcka förlustscenariot måste vi lägga till en ny variabel som vi ska använda för att stoppa blocken när de träffar GameOverArea objekt så att de inte längre kommer att röra sig. Detta kommer att göra det klart för spelaren som de har förlorat.

Global Variabel: MovementPossible Typ = Antal Initialt värde = 0

Gå nu till evenemanget där du flyttar blocken och lägg till detta villkor:

Skick: System> Jämför variabelvariabel = MovementPossible Jämförelse = Likvärdig till värde = 0

Din rörelsehändelse ska nu se ut så här:

Nu när rörelsen använder vår nya variabel, lägger vi till händelsen som upptäcker förlustförhållandet:

 Händelse: Skick: Block> Överlappar ett annat objekt Objekt = GameOverArea Skick: Omvänd: Block> IsDragging Action: Funktion> Samtalsfunktionsnamn = "Spel över"

Händelsen som vi just gör kommer att kalla funktionen Game Over en gång ett block överlappar GameOverArea. Nu ska vi faktiskt göra Gameover fungera.

 Händelse: Funktion: Funktion> På funktion Namn = "Spel över" Åtgärd: Block> Ställ in aktiverat tillstånd = Avaktiverad åtgärd: System> Ställ in värde Variabel = RörelsePossible Value = 1 Åtgärd: System> Vänta sekunder = 1,5 Åtgärd: System> Gå till layout Layout = Layout 2

Dina två nya händelser ska se ut så här:


Anledningen till att vi skapade en separat funktion istället för att göra dessa åtgärder inom händelsen som faktiskt upptäcker spelet över är att den här händelsen bara tittar på vissa block på grund av händelserna som utlöser den. Som du kan se i den funktion som vi gjorde, inaktiverar vi Blockerings dragfunktioner för att förhindra att spelaren fortsätter att skapa matcher efter att spelet över detekterats. Om vi ​​gjorde det i händelse av att det upptäckte spelet över, skulle det bara inaktivera de block som orsakade spelet över, och alla andra block skulle fortfarande kunna dras.

Gå nu till Event Sheet 2; vi ska lägga till lite funktionalitet till RestartButton objekt som vi gjorde tidigare. Lägg till en ny händelse till Event Sheet 2:

Händelse: Villkor: RestartButton> På klicka Action: System> Gå till layout Layout = Layout 1

Din händelse ska se ut så här:

Återställ värdena

Om du spelar spelet nu, ta ett spel över, och starta om, bör du märka att det går tillbaka till den ursprungliga Layouten, men blocken flyttar inte. Anledningen till detta är att alla variabler vi har använt är globala variabler, så några av dem återställs inte automatiskt när vi startar om Layout.

För att återställa dem måste vi lägga till en åtgärd till vår Vid start av layout Händelse som manuellt återställer dem för oss.

Gå till Vid start av layout Händelse och lägg till den här åtgärden till den första händelsen innan de för slingorna heter:

Åtgärd: System> Återställ globala variabler

Din händelse ska nu se ut så här:

Om du testar igen, borde du inte längre ha det här problemet.


Vad ska du göra nästa?

Vid denna tidpunkt har vi gått över alla funktioner som jag ville täcka inom ramen för dessa handledning.

Du kommer märka att ditt spel fortfarande inte är exakt samma som i demo ovan, med den största skillnaden att ditt spel inte har startskärmen. Jag valde att inte gå över skapandet av Start-skärmen, eftersom det är nästan exakt samma som att skapa Game Over-skärmen - jag lämnar detta som en övning för dig.

Istället ska jag diskutera några funktioner du kan överväga att lägga till i ditt spel som kan göra det bättre eller mer intressant.


Specialty Blocks

Det första jag vill diskutera är specialblock - block som antingen ger spelaren bonusar eller utför någon unik funktion.

De flesta Match-3-spel inkluderar specialblock som hjälper till att bryta upp åtgärden och göra spelet mer spännande. Som det står kan spelet teoretiskt gå på för evigt, men spelningen ändras aldrig. Att införa särskilda blocktyper då och då kan hjälpa till att göra spelet mer intressant när det har gått ett tag.

För att integrera ett specialblock måste du ändra hur block skapas, så att varje gång ett block skapas finns det en slumpmässig chans att det blir ett specialblock. Det finns ett antal sätt att göra detta, men i allmänhet är det bäst att bara skapa ett slumptal mellan 1 och 100 och bara skapa ett specialblock när det slumpmässiga värdet är mellan 95 och 100 eller något annat intervall som du bestämmer dig för.

Ditt mål bör vara att göra specialblock sällsynta, men inte för sällsynt. På så sätt får spelaren dem regelbundet nog för att göra spelet roligare, men inte så ofta att det förstör spelets balans.

Bomb Blocks

När det gäller specialblock har du många alternativ. en av de vanligaste är a bombblock.

Bombblock för att extrablock ska förstöras när de förstörs. De är olika i varje spel: i vissa spel förstör de alla block som omger dem; i andra förstör de en hel rad eller kolumn med block.

I bilden nedan kan du se två av bombblockstyperna från det populära spelet Candy Crush Saga:


Bombblock är vanligtvis ganska enkla att integrera:

  • Börja med en händelse som lyssnar på förstörelsen av några bombblock.
  • När man förstörs bör den passera sin position till en funktion som då kommer att hitta och förstöra alla block som också skulle förstöras av det bombsteget.
  • Om ditt bombblock förmodligen skulle förstöra alla omgivande block skulle du till exempel överföra bombblockets position till en funktion som skulle titta på var och en av de omgivande positionerna för att se om det finns några block där.
  • Om det hittar några block i dessa positioner förstör dem dem.

Time-Slow eller Time-Stop-block

En annan specialblok typ du hittar i många spel är en som saktar ner hur snabbt blocken flyttar, eller stoppar dem helt.

Block som dessa är mycket enkla att göra.

  • Precis som med bombblock, behöver du en händelse som lyssnar på när en av dessa block förstörs.
  • När detta händer bör du antingen ändra MovementsPossible till 1 så att blocken kommer att sluta, eller modifiera fart så att blocken går mycket långsamt.
  • Då bör du starta en timer som varar under en kort tid, kanske 10-15 sekunder. När den här timern slutar, återställer du blockens hastighet och fortsätter normalt.

Du måste komma ihåg att redogöra för spelaren som aktiverar ett tidsstopps block medan ett annat tidsstoppsblock redan är aktivt. I det här scenariot bör du starta om timer eller lägga till standardlängden för timern till befintlig timer och fortsätta normalt.


Andra spellägen

Du kan också överväga att lägga till andra spellägen för när spelaren blir uttråkad av det ändlösa läget vi skapade.

Timed Mode

Det enklaste spelläget att lägga till är en där spelaren har en tidsgräns, vars mål är att få så många poäng som möjligt innan tiden går ut.

I det här scenariot skulle du lämna hela spelkoden orörd, förutom att lägga till ett annat förlustvillkor för spelet, varigenom spelet slutar när timern löper ut (liksom när blocken träffar toppen av skärmen).

När spelet startar, startar du en timer för hur lång tid det går att använda, och när timern slutar skulle du avsluta spelet på samma sätt som du gör nu.

Pussel läge

I detta spelläge skulle du ge spelaren en mycket specifik spelbräda som du designar i förväg och be dem att eliminera alla block i så få swappar som möjligt.

(Du kommer noga att vilja stänga av blockrörelsen, eftersom om blocken flyttas kommer också nya block att läggas över tiden.)

Detta läge skulle kräva att du kan konfigurera ett specifikt blocknät så att du skulle behöva ha ett system som låter dig passera i en specifik blockinställning när spelet börjar snarare än att generera en helt slumpmässigt som vi gör nu.

Utöver detta, medan det här spelet är relativt lätt att implementera, skulle det kräva att du gör en massa manuell pusseldesign så att du kan skapa många unika pussel för att spelaren ska försöka lösa.

Att lägga till ett spelläge så här kan vara ganska tidskrävande på grund av all nödvändig innehållsskapande, men det finns många spelare som skulle njuta av det. Det kan verkligen fungera bra om du lägger in tiden.


Slutsats

Under denna tutorial-serie byggde vi ett helt match-3-spel från början till slut. Det finns mycket mer som du kan göra med det här spelet om du tar dig tid och har fantasin, men det finns också många sätt du kan använda de idéer jag presenterade för att hjälpa dig med andra spelprojekt.

Fortsätt att arbeta med ditt spel och fortsätt att utforska nya idéer, för att du aldrig vet när något du lärde dig här kan komma till nytta senare.

Jag hoppas att du, om du gick igenom hela serien eller bara hoppade över till de delar du inte kunde göra på egen hand, lärde dig något av det här. Om du har några problem eller kommentarer, låt oss veta i diskussionerna under varje artikel - jag skulle gärna höra från dig och se vilka vridningar du lägger till. Tack för att du läser och lyckas med dina spel!