Maak een Match-3-game in Construct 2 blokkeer beweging

In het vorige deel van deze serie hebben we enkele kleine maar belangrijke wijzigingen doorgevoerd in veel van de systemen die we hebben gemaakt voor ons Match-3-spel. Nu deze verbeteringen zijn geïmplementeerd, gaan we nu weer op het goede spoor en implementeren we een van de laatste twee belangrijke systemen voor het spel: het Block Movement-systeem.

Deze tutorial neemt je mee door de hele ontwikkeling van het systeem, waardoor de blokken naar de bovenkant van het scherm kunnen stijgen, en ook de creatie van alle kleinere systemen die we zullen moeten implementeren om het bewegingssysteem te ondersteunen. Hoewel de onderwerpen die ik in deze tutorial behandel niet zo ingewikkeld zijn, is er nog veel te over - dus laten we er even over beginnen.


Final Game Demo

Hier is een demo van de game waaraan we werken in deze serie:




1. Blokken omhoog verplaatsen

Voordat we de blokken gaan verplaatsen, moeten we een kleine verandering aanbrengen in de gebeurtenissen die de blokken spawnen. Ga naar de Systeem> Aan het begin van de lay-out evenement en verander de Y voor lus om vanaf te gaan 0 naar 3, in plaats van van 0 naar 7 zoals het oorspronkelijk deed.

Het evenement zou er nu als volgt uit moeten zien:


De reden dat we deze wijziging hebben aangebracht, is omdat we willen dat het spel begint met minder blokken op het scherm, zodat het niet zo snel eindigt als we een spel toevoegen in de volgende zelfstudie.

Vervolgens maken we een variabele die de snelheid van de blokken weergeeft:

Global Variable: Name = CurrentSpeed ​​Type = Number Value = 0.2

Nu maken we de gebeurtenis die de blokken daadwerkelijk verplaatst:

Gebeurtenis: Voorwaarde: Systeem> Elke X seconden Interval (seconden) = Huidige snelheid Actie: Blokkeren> Verplaatsen met hoek Angle = -90 Afstand = 1

Het evenement zou er als volgt uit moeten zien:


Als je het spel uitvoert na het toevoegen van deze gebeurtenis, is het eerste dat je zou moeten zien dat de blokken vallen, vanwege de zwaartekracht die we in een vorige tutorial hebben geïmplementeerd. Daarna moeten de blokken langzaam stijgen totdat ze in hun oorspronkelijke positie zijn en vervolgens weer laten vallen. Dit zal oneindig herhalen, zolang je niets doet met de Blokken.

Dit gebeurt omdat de blokken voorbij het punt gaan waar de zwaartekracht verondersteld wordt om in te trappen, en ze ontdekken dat er geen blokken onder zitten, waardoor ze allemaal vallen. Hoewel dit een probleem is, is dit niet de eerste waar ik naar wil kijken.


2. Vastzetten van swapping

Voer het spel uit en probeer een willekeurige swap uit te voeren. Wanneer je dit doet, zou je moeten zien dat de blokken achter elkaar blijven steken, vast komen te zitten in posities die niet zijn uitgelijnd met het raster en zich gewoon in het algemeen misdragen. Er zijn twee redenen voor dit probleem.

Het eerste probleem is dat, hoewel we de blokken zelf verplaatsen, we het LeftBlock, RightBlock, TopBlock, en BottomBlock objecten met hen, wat betekent dat de blokken die je gebruikt om ruilmiddelen te detecteren niet bewegen met het blokraster - ze zitten gewoon in de positie waarop ze zijn ingesteld wanneer je voor het eerst een blok oppakt.

Dus, wanneer u een ruil probeert te maken, worden de blokken uit de pas gehaald omdat de blokken voor ruildetectie helemaal niet zijn aangepast aan het raster. (Dit is ook de reden voor het tweede probleem dat we hebben, namelijk dat we de posities die we hebben opgeslagen niet wijzigen BlockPositions array ofwel.)

De onderstaande GIF demonstreert dit probleem:


Zoals je kunt zien in de GIF, bewegen de blokken voor ruildetectie niet, ook al zijn de blokken zelf.

Om deze beide problemen op te lossen, voegen we nog enkele acties toe aan het evenement dat we zojuist hebben gemaakt:

Actie: BottomBlock> Verplaats onder hoek Hoek = -90 Afstand = 1 Actie: LeftBlock> Verplaats onder hoek Hoek = -90 Afstand = 1 Actie: RightBlock> Verplaats onder hoek Hoek = -90 Afstand = 1 Actie: TopBlock> Verplaats onder hoek = -90 Afstand = 1 Actie: BlockPositions> Instellen bij XY X = 0 Y = 1 Waarde = BlockPositions.At (0,1) - 1 Actie: BlockPositions> Instellen bij XY X = 1 Y = 1 Waarde = BlockPositions.At ( 1,1) - 1

Het evenement zou er nu als volgt uit moeten zien:


De eerste vier acties die we zojuist hebben toegevoegd, passen de posities van de LeftBlock, TopBlock, RightBlock, en BottomBlock objecten zodat ze in lijn blijven met het blokraster. De tweede twee gebeurtenissen passen de Y-waarden aan die we hebben opgeslagen in de BlockPositions zodat ze ook in lijn blijven met het blokraster.

Als je het spel op dit moment opnieuw test, moet swappen meestal worden opgelost.

Op dit moment is er nog een ander probleem dat we moeten oplossen om het swappen correct te laten werken. Start het spel en probeer een neerwaartse ruil te maken met een van de blokken in de onderste rij, terwijl die rij zich gedeeltelijk onder het onderste gedeelte van het speelveld bevindt:

Maak de ruil terwijl de blokken zich achter de rand bevinden, zoals de gemarkeerde in de bovenstaande afbeelding.

Als je dit goed hebt gedaan, zou je moeten zien dat er niets is gebeurd en dat de blokken niet zijn verwisseld. Als je te lang hebt gewacht, kunnen de blokken zijn verwisseld omdat ze weer boven de rand van het speelveld zijn gekomen. Als dit is gebeurd, probeer je het opnieuw nadat ze zijn gevallen en je zou dit probleem moeten zien optreden.

Dit probleem is vrij eenvoudig op te lossen en te begrijpen. Als je de code voor neerwaartse swaps bekijkt, zou je de gebeurtenis moeten vinden die we in de vorige tutorial hebben toegevoegd, waardoor de speler geen neerwaartse swaps kan maken waardoor het blok van de onderkant van het speelveld valt. Aangezien deze verklaring de speler verhindert om neerwaartse swaps te maken wanneer de BottomBlock object is lager dan de initiële Y-positie van het blok, het voorkomt dat de blokken worden verwisseld zodra ze zijn gevallen en geeft je alleen de mogelijkheid om opnieuw swaps te maken zodra ze weer hun oorspronkelijke positie zijn gepasseerd.

Om deze verklaring te corrigeren gaan we een kleine verandering aanbrengen in de voorwaarde:

Voorwaarde: BottomBlock> Y-vergelijking vergelijken = minder of gelijk Y-coördinaat = SPAWNY + (Block.Width + 2) / 2)

De conditie zou er nu als volgt moeten uitzien:


Deze wijziging betekent dat een neerwaartse swap alleen kan plaatsvinden terwijl de BottomBlock object is maximaal een half blok onder de Y-positie waarin de blokken beginnen. Dit betekent ook dat, zodra we nieuwe rijen blokken beginnen te spuiten en ze vanaf de onderkant op het scherm schuiven, die blokken alleen kunnen worden verwisseld in op deze manier wanneer ten minste de helft van het blok zichtbaar is.

We gaan ook een vergelijkbare beperking in al onze ruilgebeurtenissen aanbrengen om ervoor te zorgen dat ze allemaal tegelijkertijd bruikbaar worden en dat een blok helemaal niet kan worden verwisseld voordat minstens de helft zichtbaar is. Nogmaals, dit zal ook helpen wanneer we het systeem integreren dat nieuwe rijen blokken oplevert. Om dit te doen, voegen we een nieuwe voorwaarde toe aan elk van de resterende drie swap-evenementen.

De voorwaarden die we toevoegen zijn precies dezelfde als degene die we zojuist hebben aangepast in de BottomBlock evenement, behalve dat ze verwijzen naar de TopBlock, RightBlock, en LeftBlock objecten in plaats van de BottomBlock object, afhankelijk van de gebeurtenis waarin het zich bevindt.

De nieuwe voorwaarde voor de TopBlock Evenement zou moeten zijn:

Voorwaarde: TopBlock> Vergelijk Y-vergelijking = minder of gelijk Y-coördinaat = SPAWNY + (Block.Width + 2) / 2)

De nieuwe voorwaarde voor de LeftBlock Evenement zou moeten zijn:

Voorwaarde: LeftBlock> Vergelijk Y-vergelijking = minder of gelijk Y-coördinaat = SPAWNY + (Block.Width + 2) / 2)

De nieuwe voorwaarde voor de RightBlock Evenement zou moeten zijn:

Voorwaarde: RightBlock> Vergelijk Y-vergelijking = minder of gelijk Y-coördinaat = SPAWNY + (Block.Width + 2) / 2)

Je geheel Op DragDrop-drop Evenement zou er nu als volgt uit moeten zien:


Met deze nieuwe voorwaarden hebben we onze ruilmechanismen hersteld en zijn we begonnen met het voorbereiden van de bestaande systemen voor het volgende systeem dat we toevoegen: het systeem dat nieuwe rijen blokken zal voortbrengen.


3. Meer blokken opspuiten

Nu we de blokken constant laten stijgen, moeten we de nieuwe rijen met blokken op het juiste moment laten spawnen en de speler toestaan ​​zo lang als ze willen door te spelen. We gaan een functie gebruiken om de nieuwe rijen blokken te laten spawnen en we gaan een gebeurtenis gebruiken die detecteert wanneer de blokken in lijn zijn met SPAWNY om die functie te activeren.

Dus laten we eerst de functie zelf maken.

Gebeurtenis: Voorwaarde: Functie> Aan functie Naam = "SpawnNewBlocks" Voorwaarde: Systeem> Voor naam = "X" Start Index = 0 Einde Index = 7 Actie: Systeem> Object maken Object = Bloklaag blokkeren = 1 X = SPAWNX + (loopIndex ( "X")) * (Block.Width + 2) Y = SPAWNY + (Block.Width + 2) Actie: Blokkeren> Instellen waarde Instantie Variabel = Kleur Waarde = vloer (Willekeurig (1,7)) Actie: Systeem> Toevoegen naar variabele = NumBlocks Waarde = 1

Je nieuwe evenement zou er als volgt uit moeten zien:


Wanneer gebruikt, maakt deze functie een rij blokken onder de onderste rij blokken in het speelveld. Zoals het er nu uitziet, gebruiken we deze functie echter op geen enkel moment, dus laten we de gebeurtenis maken die dat doet:

Gebeurtenis: Voorwaarde: Systeem> Elke X seconden Interval (seconden) = Huidige snelheid Voorwaarde: Blokkering> Vergelijk Y vergelijking = Gelijk aan Y = SPAWNY Voorwaarde: omkeren: Blokkeren> Is slepen Actie: Functie> Oproepfunctie Naam = "SpawnNewBlocks"

Je nieuwe evenement zou er als volgt uit moeten zien:


De gebeurtenis die we zojuist hebben gemaakt, controleert de Y-positie van de blokken telkens wanneer ze worden verplaatst. Als het blokken vindt die in lijn zijn SPAWNY, het triggert de SpawnNewBlocks () functie zoals we eerder hebben besproken. Het controleert ook of het gevonden blok niet degene is die door de speler wordt gesleept.

Als je nu je spel test, zal het werken, maar je zou een vreemd probleem moeten opmerken. Op het moment dat je het spel start, vallen je blokken weg alsof er geen blokken onder staan, maar na dat punt werkt alles perfect, en nieuwe blokken worden uitgezet wanneer ze nodig zijn.

Dit gebeurt omdat, wanneer het spel voor het eerst start, het de zwaartekrachtcode verwerkt voor de code die nieuwe rijen met blokken spawnt. Om dit op te lossen, gaan we een kleine aanpassing maken aan de code die de eerste groep blokken spawnt, zodat ze worden uitgelokt tot onder het punt waar een nieuwe rij nodig zou zijn. Hierdoor kan het voorkomen dat de zwaartekrachtcode onmiddellijk wordt gebruikt en kan deze de nieuwe rij blokken maken zodra de bestaande blokken op de juiste locatie staan.

Ga naar de gebeurtenis die de eerste groep blokken spawnt en wijzig de actie die het blok daadwerkelijk maakt. Verander de actie in deze:

Actie: Systeem> Object maken Object = Laag blokkeren = 1 X = SPAWNX + (loopIndex ("X")) * (Block.Width + 2) Y = SPAWNY - (loopIndex ("Y")) * (Block.Width + 2) + 5

Het evenement zou er nu als volgt uit moeten zien:


Deze wijziging betekent dat de blokken vijf pixels lager zullen spawnen SPAWNY. Dit betekent dat de blokken vijf keer hoger moeten zijn voordat een nieuwe rij zal spawnen en ons probleem oplost.


4. Een beetje animatie

Op dit punt zijn onze blokken in beweging en we hebben nieuwe rijen gemaakt. Vergeet niet dat we eerder hebben voorkomen dat de speler een blok gebruikt totdat ten minste de helft van het blok zichtbaar is. Hoewel dit een goede functie is, begrijpt de speler misschien niet waarom een ​​blok niet onmiddellijk kan worden gebruikt wanneer het zichtbaar wordt, zelfs als er niet veel van zichtbaar is op het moment.

Vanwege dit mogelijke probleem met de gebruikersinterface, laten we elk blok de grijze bloksprite gebruiken (aan het begin van de animatieframes van het blok) wanneer deze in deze onbruikbare staat is. Dit maakt de speler duidelijk wanneer een blok bruikbaar wordt en geeft ons de kans om eindelijk onze laatste block-afbeelding te gebruiken.

Je kunt een voorbeeld zien van hoe het eruit zal zien als de blokken inactief worden van inactief naar actief in de GIF hieronder:


De gebeurtenis die we maken, bevat ook een tweede voorwaarde die controleert of het blok waarnaar wordt gekeken niet wordt gesleept. Deze voorwaarde stelt ons in staat om ervoor te zorgen dat wanneer de speler een blok sleept onder het punt waar blokken bruikbaar worden, het zijn afbeelding niet zal veranderen zodat het grijs is en de kleur behoudt die het hoort te zijn.

Om deze animatie te laten werken, moeten we eerst een nieuw evenement toevoegen:

Gebeurtenis: Voorwaarde: Blok> Vergelijk Y-vergelijking = Groter dan Y = SPAWNY + ((Block.Width + 2) / 2) Voorwaarde: Omkeren: Blokkeren> Is Slepen Actie: Blokkeren> Frame instellen Framenummer = 0

Het nieuwe evenement zou er als volgt uit moeten zien:


Je zou nu je spel moeten kunnen testen en je zou moeten zien dat de blokken de grijze afbeelding gebruiken als ze onder het punt zijn waarop ze bruikbaar worden.


5. Slepen / neerzetten in- en uitschakelen

Als je het spel nu uitvoert, zul je merken dat hoewel de blokken niet met elkaar kunnen worden verwisseld wanneer ze grijs zijn, de grijze blokken nog steeds kunnen worden gesleept en gemanipuleerd. Dit komt omdat we de Drag / Drop-mogelijkheden van het blok nooit hebben uitgeschakeld toen we verhinderden dat de speler ermee zou swappen.

Om te voorkomen dat de grijze blokken kunnen worden verplaatst, passen we de gebeurtenis aan die we in het vorige gedeelte hebben gemaakt. Eerst voegen we een nieuwe actie toe die het slepen uitschakelt wanneer het blok zich onder het punt bevindt waarop het bruikbaar wordt.

Voeg deze actie toe aan het evenement dat we eerder hebben gemaakt:

Actie: blokkeren (DragDrop)> Ingesteld staat instellen = Uitgeschakeld

We gaan ook een Else-verklaring toevoegen voor deze gebeurtenis, waardoor het blok opnieuw kan worden gesleept als het zich boven het punt bevindt waarop het blok bruikbaar wordt:

Gebeurtenis: Voorwaarde: anders Actie: blokkeren (DragDrop)> Ingesteld staat instellen = Ingeschakeld

Met beide wijzigingen zou het evenement er als volgt uit moeten zien:


Als je het spel op dit moment test, mogen de blokken niet langer bruikbaar zijn als ze grijs zijn en moeten ze werken zoals ze altijd zijn als ze niet zijn.


6. Snelheidswijzigingen

Het laatste dat ik in dit artikel wil bespreken, is het systeem waarmee we de snelheid van het spel in de loop van de tijd kunnen veranderen. In het bijzonder is dit het systeem dat ervoor zorgt dat de blokken sneller bewegen omdat de speler er meer van elimineert.

Het systeem dat we gaan maken is relatief eenvoudig: elke keer dat de speler een bepaald aantal punten krijgt, zal de snelheid van het spel toenemen op basis van een modifier die we gaan maken, en het aantal punten dat de speler moet krijgen de volgende snelheidsverhoging zal veranderen op basis van een tweede modificator.

Voordat we daadwerkelijk de gebeurtenissen voor dit systeem kunnen maken, maken we een aantal globale variabelen om de nieuwe functies voor ons te verwerken:

Globale variabele: SPEEDMOD Type = Number Beginwaarde = 0.8 Constant = Ja Globale variabele: PointsForSpeedUp Type = Nummer Beginwaarde = 400 Constante = Geen globale variabele: PuntenTussenSpeedUps Type = Aantal Beginwaarde = 400 Constante = Geen globale variabele: POINTSFORSPEEDUPMOD Type = nummer Eerste waarde = 1,4 constant = Ja

Uw nieuwe variabelen moeten er als volgt uitzien:


Nu we de variabelen op zijn plaats hebben, zal ik uitleggen wat elk doet.

  • SPEEDMOD is de variabele die we de snelheid zullen vermenigvuldigen door hem te wijzigen telkens wanneer de speler het aantal punten bereikt dat hij nodig heeft om een ​​snelheidsverhoging te veroorzaken.
  • PointsForSpeedUp is het aantal punten dat de speler nodig heeft om de volgende snelheid te halen.
  • PointsBetweenSpeedUps geeft aan hoeveel de PointsForSpeedUp variabele zal toenemen wanneer de speler sneller wordt, om hem aan te passen, zodat de volgende snelheid nog meer punten oplevert. Op dit moment is het 400, zoals PointsForSpeedUp, maar wanneer de speler daadwerkelijk sneller wordt, wordt deze vermenigvuldigd met POINTSFORSPEEDUPMOD voordat het wordt toegevoegd aan PointsForSpeedUp.
  • Tenslotte, POINTSFORSPEEDUPMOD is de variabele die we zullen gebruiken om het aantal punten aan te passen dat de speler nodig heeft om zijn snelheid te verhogen, een andere keer dan degene die hij het laatst kreeg.

Naast het instellen van de variabelen, moeten we ook een nieuw sprite-object maken dat als waarschuwing voor de speler fungeert wanneer de snelheid toeneemt.

Ga naar Layout 1 en volg deze stappen om de nieuwe sprite te maken:

  1. Plaats een nieuw sprite object aan Layout 1.
  2. Open de afbeelding met de animatie-editor SpeedIncImage.png.
    1. Stel de Naam naar SpeedIncreaseIndicator.
    2. Stel de Laag naar Game Field.
    3. Stel de Positie naar 188, 329.
    4. set Eerste zichtbaarheid naar Onzichtbaar.
      1. Voeg een ... toe Vervagen Gedrag naar de Sprite.
      2. set Actief bij Start naar Nee.
      3. Stel de Fade out tijd naar 2.5.
      4. set Vernietigen naar Nee.

Uw lay-out zou er nu als volgt uit moeten zien:


Nu zullen we feitelijk het evenement maken dat de snelheid verandert:

Evenement: Voorwaarde: Functie> Aan functie Naam = "CheckForSpeedUp" Voorwaarde: Systeem> Variabele vergelijken Variabel = Scorevergelijking = Groter of gelijk Waarde = PuntenForSpeedUp Actie: Snelheidsverhoogde indicator> Zichtbaar instellen Zichtbaarheid = Zichtbare actie: Snelheidsverhoogde indicator> Start vervagen Actie-systeem> Stel waarde in Variable = CurrentSpeed ​​Value = CurrentSpeed ​​* SPEEDMOD Action System> Stel waarde in Variable = PointsBetweenSpeedUp Value = PointsBetweenSpeedUp * POINTSFORSPEEDUPMOD Actie: Systeem> Toevoegen aan variabele = PuntenForSpeedUp-waarde = PuntenTussenVanSpeedUp

Uw evenement zou er als volgt uit moeten zien:


Wanneer deze functie wordt aangeroepen, wordt gecontroleerd of de speler genoeg punten heeft gescoord om een ​​snelheidsverhoging te rechtvaardigen. Als ze dat hebben, dan:

  • het activeert de sprite die de speler vertelt dat de snelheid is toegenomen door deze zichtbaar te maken en de Fade te starten
  • het verhoogt de snelheid door het te vermenigvuldigen met de modifier
  • het bepaalt het aantal punten dat nodig is voor de volgende versnelling, en
  • het voegt die waarde toe aan het totale aantal punten dat de speler moet hebben voordat de snelheid weer toeneemt.

Als deze functie is voltooid, moeten we ervoor zorgen dat deze wordt gebeld. Ga naar de GivePoints () functie en voeg deze actie toe aan het einde van de primaire gebeurtenis en de subgebeurtenis:

Actie: Functie> Oproepfunctie Name = "CheckForSpeedUp"

De GivePoints () functie zou er nu als volgt uit moeten zien:


Met dat evenement moet je je spel kunnen testen en het versnellingssysteem in actie kunnen zien.

Tip: Toen ik er meer mee speelde, merkte ik dat deze waarden een beetje wegden, dus ik raad aan dat je wat tijd neemt om met het systeem te experimenteren en de waarden te vinden die je het prettigst vindt.


Conclusie

We hebben in dit artikel veel verschillende onderwerpen behandeld, maar alles wat we hebben behandeld, heeft direct of indirect te maken met het feit dat het bewegingssysteem werkt zoals we wilden. Hoewel het enige tijd duurde en we moesten meer systemen maken dan we in het begin hadden verwacht, was de uitbetaling de moeite waard en we eindigden uiteindelijk met een zeer sterk systeem.

Vanwege hoeveel we al hebben behandeld, denk ik dat dit een goede plek is om dit artikel te beëindigen. Het volgende artikel zou de laatste zelfstudie in deze serie moeten zijn en we zullen er veel kleinere onderwerpen in behandelen, maar het grootste dat we behandelen is zeker de eliminatie van vooraf gemaakte matches.

Als je wilt proberen te achterhalen hoe we ze zullen elimineren, kijk dan eens naar hoe we wedstrijden herkennen om mee te beginnen. Het systeem dat we maken zal sterk op dat systeem lijken, behalve dat het de gevonden overeenkomsten op een andere manier zal gebruiken. Begin erover na te denken en zie wat je kunt verzinnen, en ik zal je hier de volgende keer terug zien voor de laatste grote tutorial in de serie.