Gör ett match-3-spel i konstruktion 2 poäng, matchning och tyngd

I den tidigare handledningen integrerade vi ett grundläggande matchningsdetekteringssystem i vårt Match-3-spel. Medan vi är väl på väg att ha ett spelbart spel finns det fortfarande några viktiga spelelement vi behöver innan vi verkligen kan ringa vad vi har ett "spel". Denna artikel kommer att fokusera på att fylla i några av de saknade detaljerna och få oss mycket närmare vår slutprodukt.


Final Game Demo

Här är en demonstration av spelet vi arbetar mot genom hela serien:




1. Tilldelningspoäng

Vi ska täcka punkter innan vi börjar förbättra matchningssystemet, eftersom det blir mycket lättare att se den första frågan i vårt nuvarande matchningssystem om vi har ett poängsystem implementerat.

Poängsystemet i vårt spel kommer att bli väldigt enkelt, för varje Block som används för att bilda en viss grupp, kommer spelaren att få 10 poäng. I en senare handledning lägger vi också till ett system som gör det möjligt för spelaren att få fler poäng genom att kedja ihop flera grupper, men för nu kommer vi att fokusera på att bara introducera ett enkelt poängsystem för spelaren.

Innan vi börjar redigera händelserna måste vi lägga till en poängdisplay, så först gå till Layout 1 och gör följande:

  1. Lägg in en ny Sprite objekt.
    1. Öppna bilden Game Field Bilder / ResultatArea.png från grafikpaketet.
    2. Stäng animeringsredigeraren.
    3. Ställ in läget till 491, 383.
  2. Lägg in en ny Text objekt.
    1. Ställ in Font till Calibri, fet, 22 med hjälp av rullgardinsmenyn.
    2. Ställ in namn till ScoreText
    3. Ställ in Färg till Vit eller 255, 255, 255
    4. Ställ in Placera till 419, 398.
    5. Ställ in Storlek till 200, 50.
    6. Ställ in Text till 0.

Layout 1 ska nu se ut så här:

Nu när vi har något att berätta för spelaren vad punkten betyder, och ett textobjekt för att visa spelarens poäng med, kan vi gå vidare för att faktiskt ge spelaren poäng. Gå till Event Sheet 1 och skapa en ny Global variabel.

Global Variable Name: "Score" Type = Nummervärde = 0

Variabeln ska se ut så här:

Detta är variabeln som vi kommer att ändra när vi ger spelaren poäng. Därefter kommer vi att skapa en ny funktion som när den kallas kommer att upptäcka hur många block som spelaren har matchat i grupper och ge dem ett lämpligt antal poäng.

Händelse: Villkor: Funktion> På Funktionsnamn = "GivePoints" Skick: System> För varje objekt = Blocktillstånd: Block> Är boolean instans variabel inställd Instansvariabel = IsMatched Action: System> Lägg till Variabel = Poängvärde = 10 Åtgärd: ScoreText > Ange text Text = Poäng

Din kod ska se så här ut:

Så, för att upprepa, ser denna händelse på varje enskild block. Varje gång det hittar ett block som har IsMatched satt till Sann - vilket betyder att det har bekräftats att ingå i en grupp - det ger spelaren 10 poäng för det Block, och uppdaterar poängtexten.

Om du testar ditt spel vid denna tidpunkt verkar det som om funktionen inte fungerar. Orsaken till detta beror på att vi inte faktiskt har ringt funktionen någonstans i koden, så att punkterna aldrig ökas, och texten uppdateras aldrig. Gå till din FindMatches funktionen och lägg till en ny åtgärd till början av den sista delhändelsen för den här funktionen.

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

Din FindMatches funktionen ska nu se ut så här:

Obs! Se till att du har lagt till den här nya åtgärden i början av delhändelsen. Om du lägger till den här åtgärden till slutet, fungerar den inte eftersom alla matchade block kommer att ha förstörts före GivePoints funktion kallas. Det betyder att när det söker efter matchade block kommer det inte att hitta någon och så kommer spelaren inte att få några poäng.

Vid denna tidpunkt kan du testa ditt spel igen och du ska se uppdateringen av poängtexten och att spelaren får rätt antal poäng för varje match de gör.


2. Förbättra matchdetektering

Nu när vi har poängsystemet, vill jag att du ska springa spelet och skapa scenariot som visas nedan.


Byt nu de block jag har markerat här och kolla in din poäng för att se hur många poäng du får.


När du bildade den här matchen borde du ha sett att du fick 50 poäng. Detta beror på att poängsystemet för närvarande ger spelaren 10 poäng för varje Block som är markerat som IsMatched, i motsats till att ge spelaren 10 poäng för varje block Begagnade i varje match, som systemet jag beskrev ovan.

Om poängsystemet fungerade korrekt skulle det ge spelaren 60 poäng: 30 för den vertikala gruppen av tre kvarter och 30 för den horisontella gruppen av tre kvarter. Problemet härrör från det faktum att matchningssystemet inte har någon markering när ett block matchas både horisontellt och vertikalt; det vet bara om blocket är matchat alls.

För att lösa detta problem kommer vi först att lägga till två nya Instansvariabler till vårt blockobjekt, MatchedX och MatchedY.

Instansvariabel: Namn = MatchedX Typ = Boolean Initial Value = Fel Instansvariabel: Namn = MatchedY Type = Boolean Initial Value = Falskt

Dina variabler ska se ut så här:


Dessa variabler kommer att användas tillsammans med IsMatched att berätta för systemet när Block är en del av horisontella eller X, och när Block är en del av vertikala eller Y-grupper. Nu när vi har variablerna, kommer vi att ändra CheckMatches funktion så att när det märker ett block IsMatched eftersom den hittade en tillräckligt stor grupp, kommer den också att märka det blocket som en del av en X- eller Y-grupp beroende på om parameter 3 eller parameter 4 är 1.

Gå till CheckMatches funktionen och byt ut originalet NumMatchesFound kolla med dessa två nya underevenemang:

Sub-Event: Condition: System> Jämför två värden Första värdet = Function.Param (3) Jämförelse = Gäller till andra värde = 1 Skick: System> Jämför variabelvariabel = NumMatchesFound Comparison = Större eller lika värde = 3 Åtgärd: Block> Set Boolean Instance variabel = IsMatched Value = Sann Åtgärd: Block> Ställ in Boolean Instance variabel = MatchedX Value = Sann Sub-Event: Skick: System> Jämför två värden Första värdet = Function.Param (4) Jämförelse = Gäller till Second value = 1 Skick : System> Jämför variabel variabel = NumMatchesFound Comparison = Större eller lika värde = 3 Åtgärd: Block> Ställ in Boolean Instance variabel = IsMatched Value = Sann åtgärd: Blockera> Ställ in Boolean Instance variabel = MatchedY Value = True

Din CheckMatches funktionen ska nu se ut så här:


Så den nya versionen av CheckMatches fungerar på samma sätt som den föregående, förutom att det nu också kontrolleras om blocket befanns vara en matchning i en vertikal grupp eller en horisontell grupp och märker blocket i enlighet med de nya variablerna MatchedX och MatchedY.

Tilldela extra poäng till block som matchar två gånger

Nu när vi har ett sätt att bestämma när ett block matchas vertikalt, matchas det horisontellt och matchas i båda riktningarna, i motsats till att bara veta att det har matchats i en grupp, måste vi lägga till en delhändelse till GivePoints funktion som kommer att distribuera ytterligare 10 poäng för ett block som har båda MatchedX och MatchedY satt till true.

Gå till GivePoints funktion och lägg till den här delhändelsen:

Sub-Event: Skick: Block> Är Boolean Instans variabel inställd Instansvariabel = MatchedX Skick: Block> Är Boolean Instans variabel inställd Instansvariabel = MatchedY Åtgärd: System> Lägg till Variabel = Poäng Värde = 10 Åtgärd: Text> Ange text Värde = Göra

Din GivePoints funktionen ska nu se ut så här:


Om du kör ditt spel och igen skapar scenariot jag illustrerade ovan ska din poäng nu höja med 60 poäng.


3. Lägger tyngd

Nu när vi har ett Points-system implementerat, och vi har uppdaterat matchningssystemet, kommer vi att börja förbättra en annan viktig aspekt av spelet. Om du har spenderat någon gång med spelet fram till den här tiden kommer du att veta att en av de största problemen är att när block förstörs händer ingenting med blocken ovanför dem. Specifikt faller blocken ovanför tomma utrymmen inte för att fylla i dessa utrymmen.

Det här är bra i testen, men i den slutliga versionen skulle det vara skadligt för spelet att lämna saker som de är, så det nästa vi lägger till är "gravitation" som kommer att få blocken att falla och fylla i tomma utrymmen när andra block förstörs.

Det sätt som vi kommer att implementera detta system är faktiskt ganska enkelt. Vi gör en check med Block> Överlappar vid förskjutning händelse för att se om det finns ett block under det block vi tittar på. Om vi ​​finner att det inte finns något block, kommer vi att flytta blocket vi tittar ner för att fylla i det tomma rummet; annars gör vi ingenting.

För att göra detta arbete kommer vi att skapa en ny händelse:

Händelse: Skick: INVERT> Block> Överlappar vid förskjutning Objekt = Block Offset X = 0 Offset Y = 8 Åtgärd: Block> Flytta i vinkel Vinkel = 90 Avstånd = (Block.Width + 2) / 2

Din kod ska se så här ut:


Om du kör spelet vid den här tiden kommer du att se att det ögonblick som spelet börjar, faller alla block från skärmen! Anledningen till detta beror på att vi inte sätter något i koden för att berätta för var "golvet" i spelfältet skulle vara.

Så i huvudsak inser blocken på den nedre raden att det inte finns några block under dem och faller därefter. Då, när den lägsta raden av Block har fallit, ser nästa nedre raden att det nu inte finns några block under dem, och de faller också. Denna process fortsätter tills alla blocken har fallit och lämnar skärmen helt tom.

Du kan se en lite långsam version av detta i åtgärd i GIF nedan:


För att fixa detta lägger vi till ett andra villkor för händelsen.

Händelse: Skick: Block> Jämför Y Jämförelse = Mindre eller lika Y = SPAWNY - 1

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


Genom att lägga till detta nya villkor ser vi till att endast block som ligger över Y-läget för den lägsta raden påverkas av vår "gravitation". Trots detta har vi fortfarande några problem.

Hantera med att dra

Det främsta problemet är att händelsen som ser ut om det finns ett tomt utrymme under ett block inte har något att säga att det är inaktivt när spelaren drar ett block. Detta innebär att om du drar ett block för långt utan att släppa det, kommer blocken i positionen ovanför där du släpade den från att falla in i det utrymme som lämnas av blocket du slog. Utöver det kommer det block du drar också att få problem om du tar ut det från spelfältet och det börjar falla bort från muspekaren eftersom det inte finns några block under det.

För att åtgärda detta problem måste vi lägga till en ny global variabel för att berätta för systemet när vi flyttar ett block, en ny åtgärd till blocket dra och släpp händelser för att ställa in denna globala variabel och ett tredje villkor för gravitationen så det tar Denna variabel beaktas innan den aktiveras.

Låt oss först göra den globala variabeln:

Global Variabel: Namn = BlockBeingMoved Type = Antal Initial Value = 0

Din variabel ska se ut så här:


Gå nu till På DragDrop dra start händelse och lägg till en ny åtgärd:

Åtgärd: System> Ange värdevariabel = BlockBeingMoved Value = 1

Gå också till På DragDrop droppe händelse och lägg till en ny åtgärd till den primära händelsen:

Åtgärd: System> Ange värdevariabel = BlockBeingMoved Value = 0

Med de tillagda linjerna bör dina DragDrop-händelser nu se ut så här:


Slutligen, gå till gravitationen och lägg till ett nytt villkor:

Skick: System> Jämför Variabel Variabel = BlockBeingMoved Comparison = Likvärdig till värde = 0

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


Den nya variabeln som vi skapade, BlockBeingMoved, används för att berätta för systemet när ett block flyttas av spelaren. Om variabeln är lika 0 det betyder att inget block flyttas och det kan springa gravitationsskript som vanligt. Om variabeln är lika 1, det betyder ett block är flyttas och gravitationskripten ska inte köras.

Om du kör spelet vid denna tidpunkt kommer du att se att oavsett var du flyttar blocket medan du drar det, inträffar inga problem.

Kontrollera efter nya matcher

Nu har vi bara en sista fråga för att hantera tyngdkraftsystemet. Kör spelet och skapa ett scenario som liknar detta:


Gör nu den byte jag har markerat i den här nästa bilden.


Du bör märka att när gruppen Green / Star Blocks förstörs faller en Orange / Hexagon Block och bildar en grupp av tre Blocks, men blir inte förstörda.

Anledningen till att dessa block inte blir förstörda är att vi aldrig kallade FindMatches fungera en andra gång för att se om några nya matchningar bildades när blocken föll för att fylla i tomma utrymmen. För att åtgärda detta, gå till händelsen som kontrollerar tomma utrymmen under Block och lägg till den här Else Event:

Händelse: Skick: System> Övrig åtgärd: Funktion> Samtalsfunktion Namn = "FindMatches"

Din kod ska se så här ut:


Detta annat uttalande innebär att när det finns inga tomma utrymmen, kommer det att utföra en kontroll för att se om det finns några grupper att förstöra. Denna händelse kommer automatiskt att köras när Block faller i nya positioner eftersom det aktiveras av ett annat uttalande som är kopplat till den kontrollen och kommer bara att avfyra när det är säkert att alla blocken har fallit på plats.

Om du kör spelet vid denna tidpunkt kommer du att upptäcka att du nu kan skapa kedjor av block genom att förstöra block på ett sätt som grupper kommer att bildas när de återstående blocken faller. Utöver det kommer du också att upptäcka att när du först börjar spelet kommer alla grupper som skapas i början förstörs också. Som jag sa i den tidigare handledningen kommer vi till slut att eliminera färdiga matchningar, så det här problemet kommer inte att göra något i slutändan.

Ta bort block från den ursprungliga layouten

Slutligen måste vi göra en annan sak innan vi kan överväga vårt tyngdkraftsystem komplett. Beroende på var du placerat den ursprungliga Block-sprite när du genomförde den första handledningen kan du märka att när du börjar spelet faller det och blir synligt.

Om du inte vet vad jag menar, gå till Layout 1, Ställ in din Block Sprite position till 521, -32, och kör spelet. När du spelar spelet borde du se den ursprungliga Block land i den position jag har markerat i bilden nedan:


Som du kan se i bilden ovan faller det ursprungliga blocket från sin position utanför skärmen och blir synlig. Vi vill inte ha det här eftersom det bara kommer att orsaka oss problem senare. För att lösa detta lilla problem ska vi lägga till en åtgärd till Vid start av layout händelse som kommer att förstöra alla block som finns i layouten när det initialt laddas.

Åtgärd: Blockera> Förstör

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


Nu när du kör spelet, borde du inte längre se Block. Du kanske frågar dig varför vi inte bara tog bort blocket från Layout så vi behöver inte oroa dig för det här problemet alls. Anledningen till att vi inte gjorde det här är att Construct 2 inte kan skapa kopior av någon objekttyp med händelser, såvida det inte redan finns en förekomst av objekttypen i spelet när den först laddas. Genom att radera det inom en händelse tar vi bort det så att det inte blir ett problem senare, och vi gör det möjligt att gissa så många block som vi behöver genom kod.


Slutsats

Vi täckte många ämnen i den här handledningen och medan det finns mer vi kan göra tycker jag att det är viktigt att ta en paus och låt denna information sjunka in. I nästa del kommer vi att fixa ett par små problem, göra Den fancy flytande punkttexten som du kanske har lagt märke till är i den slutliga demoen och sätter upp kedjesystemet.

Jag hoppas att du fick mycket av den här delen av serien, och jag kommer se dig tillbaka här nästa vecka.