Machen eines Match-3-Spiels in Construct 2: Match-Erkennung
German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)
Bisher wurden in dieser Serie die Grundlagen zum Einrichten eines Match-3-Spiels und zum Implementieren der anfänglichen Gameplay-Elemente wie Block-Swapping behandelt. In diesem Tutorial werden wir darauf aufbauen und feststellen, wann der Spieler ein Match gemacht hat.
Finale Spiel-Demo
Hier ist eine Demo des Spiels, auf das wir in dieser Serie hinarbeiten:
1. Erkennen eines Matches
Im Moment werden wir nur eine Basisversion des Matching-Systems implementieren, wobei wir uns darauf konzentrieren, herauszufinden, wann Matches vorhanden sind, und übereinstimmende Blöcke zerstören. In späteren Artikeln werden wir das System weiterentwickeln und weiterentwickeln.
Tipp: Sie sollten lesen, wie eine rekursive Funktion funktioniert, wenn Sie es noch nicht wissen. Im Wesentlichen ist es eine Funktion, die sich selbst aufruft. Rekursive Funktionen können ähnlich wie Schleifen funktionieren, aber da sie auch Variablen aufnehmen und zurückgeben können, haben sie viel mehr Verwendungsmöglichkeiten als Schleifen.
Wie im vorherigen Tutorial möchte ich zunächst die Funktionsweise des Systems erläutern und dann versuchen, es zu erstellen.
- Das Match-System durchläuft jede Instanz des
Block
-Objekts. - Für jeden
Block
wird die Farbe und Position des Blocks, den er betrachtet, in eine rekursive Funktion übergeben, die den horizontalen oder vertikalen Nachbarn betrachtet und feststellt, ob sie dieselbe Farbe haben. - Wenn ein Match gefunden wird, wird die Funktion erneut mit der Position und Farbe des neuen Blocks und nicht mit dem ursprünglichen Block aufgerufen.
- Dies wird fortgesetzt, bis kein Match mehr gefunden wird. Zu diesem Zeitpunkt wird überprüft, wie viele Matches gefunden wurden.
- Wenn drei oder mehr Matches gefunden wurden, werden alle Blöcke markiert
Matched
, die gerade als mit derIsMatched
-Instanzvariablen übereinstimmend angesehen wurden, die wir in einem der vorherigen Tutorials erstellt haben. sonst macht es nichts. - Sobald alle Blöcke überprüft wurden, zerstört die Funktion jeden Block, der als Match markiert ist.
Zunächst benötigen wir ein Event, das jeden Block
durchlaufen kann. So wie ich das System aufgebaut habe, durchläuft es die Blöcke tatsächlich zweimal: einmal, um nach vertikalen Matches zu suchen, und einmal, um nach horizontalen Matches zu suchen. Abhängig davon, welche Prüfung durchgeführt wird, wird eine andere Funktion verwendet, um tatsächlich nach dem Match zu suchen.
Das allererste, was wir tun müssen, ist eine globale Variable zu erstellen, um zu verfolgen, wie viele übereinstimmende Blöcke wir in einer bestimmten Iteration gefunden haben:
Global Variable Name: "NumMatchesFound" Type = Number Value = 0
Lassen Sie uns nun das Event erstellen, das die Blöcke durchläuft:
Event: Function > On function Name: "FindMatches" Sub-Event: System > For Each Object: Block Action: System > Set value NumMatchesFound = 1 Action: Function > Call function Name: "CheckMatchesX" Parameter 0: Block.X Parameter 1: Block.Y Parameter 2: Block.Color Sub-Event: System > Compare Variable NumMatchesFound >= 3 Action: Block > Set Boolean IsMatched = True Sub-Event: System > For Each Object: Block Action: System > Set value NumMatchesFound = 1 Action: Function > Call function Name: "CheckMatchesY" Parameter 0: Block.X Parameter 1: Block.Y Parameter 2: Block.Color Sub-Event: System > Compare Variable NumMatchesFound >= 3 Action: Block > Set Boolean IsMatched = True Sub-Event: Block > Is Boolean instance variable set System > Wait Second = 0.1 Block > Destroy
Ihr Code sollte folgendermaßen aussehen:



In diesem Fall durchlaufen wir jeden Block und senden sie an CheckMatchesX
oder CheckMatchesY
, die Funktionen, die prüfen, ob der benachbarte Block übereinstimmt.
Um den Block in die Funktion zu senden, übergeben wir den Funktionen drei verschiedene Parameter:
- Parameter 0 ist die X-Position des Blocks
- Parameter 1 ist die Y-Position des Blocks
- Parameter 2 ist die Farbe.
Nachdem jeder Block an eine der Funktionen gesendet wurde und die Ausführung der Funktion beendet ist, überprüft er NumMatchesFound
, um festzustellen, ob drei oder mehr übereinstimmende Blöcke gefunden wurden, und kennzeichnet die Blöcke dann als Matched
, falls dies der Fall ist.
Schließlich wird jeder Block, der als Matched
markiert ist, nach Ablauf von 0,1 Sekunden zerstört. Diese wait
-Anweisung dient dazu, dem Spiel zu ermöglichen, die Bilder für die Blöcke auf das Bild umzustellen, das angibt, dass sie übereinstimmen, und dem Spieler einen Moment Zeit zu geben, um diese Änderung zu bemerken.
(Während Sie die wait
-Anweisung entfernen können, ohne das Gameplay negativ zu beeinflussen, erleichtert dies dem Spieler das Verständnis und verlangsamt das Spiel gerade so weit, dass der Spieler leicht verfolgen kann, was gerade passiert.)
2. Die zwei Prüffunktionen
Als nächstes müssen wir die Funktionen CheckMatchesX
und CheckMatchesY
ausführen. Diese Funktionen funktionieren ähnlich wie die obigen Iteratoren, da es eine Version zum Überprüfen horizontaler Matches, CheckMatchesX
, und eine für vertikale Matches, CheckMatchesY
, gibt.
Horizontale Prüfungen
Lassen Sie uns zunächst die horizontale Überprüfungsfunktion erstellen:
Event: Function > On function Name: "CheckMatchesX" Sub-Event: Condition: Block > Compare X X = Function.Param(0) + (Block.Width+2) Condition: Block > Compare Y Y = Function.Param(1) Condition: Block > Compare instance variable Color = Function.Param(2) Action: System > Add to Variable = NumBlocks Value = 1 Action: Function > Call function Name: "CheckMatchesX" Parameter 0: Function.Param(0) + (Block.Width+2) Parameter 1: Function.Param(1) Parameter 2: Function.Param(2) Sub-Event: System > Compare Variable NumMatchesFound >= 3 Action: Block > Set Boolean IsMatched = True
Ihr Code sollte folgendermaßen aussehen:



Was macht diese Funktion?
- Zunächst wird geprüft, ob links von dem Block, den wir übergeben haben, überhaupt ein benachbarter Block vorhanden ist.
- Sobald die Funktion bestätigt, dass sich am benachbarten Speicherort ein Block befindet, prüft sie, ob er dieselbe Farbe wie der Block hat, den wir übergeben haben.
- Wenn dies der Fall ist, wird
NumMatchesFound
um eins erhöht und der neu gefundene Block wird wie beim Original an die Funktion übergeben. - Dies wird fortgesetzt, bis ein Block gefunden wird, der nicht die gleiche Farbe wie das Original hat. Zu diesem Zeitpunkt wird überprüft, ob genügend übereinstimmende Blöcke gefunden wurden, um eine Gruppe zu erstellen, und die Blöcke werden als Matches gekennzeichnet, wenn dies der Fall ist.
Vertikale Überprüfungen
Lassen Sie uns nun eine andere Version dieser Funktion erstellen, die dasselbe für vertikale Matches tut. Dies wird unsere CheckMatchesY
-Funktion sein. Sie können entweder die ursprüngliche Funktion kopieren und alle entsprechenden Änderungen vornehmen oder sie einfach von Grund auf neu erstellen. In beiden Fällen sollte Ihre Funktion nach Abschluss folgendermaßen aussehen:
Event: Function > On function Name: "CheckMatchesY" Sub-Event: Condition: Block > Compare X X = Function.Param(0) Condition: Block > Compare Y Y = Function.Param(1) + (Block.Width+2) Condition: Block > Compare instance variable Color = Function.Param(2) Action: System > Add to Variable = NumBlocks Value = 1 Action: Function > Call function Name: "CheckMatchesY" Parameter 0: Function.Param(0) Parameter 1: Function.Param(1) + (Block.Width+2) Parameter 2: Function.Param(2) Sub-Event: System > Compare Variable NumMatchesFound >= 3 Action: Block > Set Boolean IsMatched = True
Ihr Code sollte folgendermaßen aussehen:



3. Eigentlich nach Checks suchen
Schließlich müssen wir die FindMatches
-Funktion tatsächlich aufrufen. Gehen Sie zur SwapBlocks
-Funktion und fügen Sie am Ende der Funktion ein neues Unterevent hinzu:
Event: Function > Sub-Event: Action: Function > Call function Name: "FindMatches"
Sie werden feststellen, dass dieses Unterevent keine Bedingungen hat. Wenn Sie noch nie ein Unterevent wie dieses erstellt haben, erstellen Sie einfach ein Untererevent mit einer beliebigen Bedingung, da Sie beim Erstellen eines Untererevents eine Bedingung angeben und löschen Sie dann die Bedingung, lassen Sie aber das Untererevent stehen. Auf diese Weise stellen Sie sicher, dass das Unterevent immer ausgeführt wird.
Ihr SwapBlocks
-Event sollte jetzt folgendermaßen aussehen:



Wenn Sie das Spiel zu diesem Zeitpunkt ausführen, werden Sie feststellen, dass die Blöcke bei Matches zerstört werden. Sie werden jedoch auch feststellen, dass alle Matches, die zu Beginn des Spiels vorhanden sind, erst verschwinden, wenn Sie einen Tausch durchführen. Dies liegt daran, dass wir die FindMatches
-Funktion niemals aufrufen, nachdem wir das Blockraster erstellt haben.
Der Grund, warum wir diesen Code nicht hinzugefügt haben, ist, dass es in der endgültigen Version eine weitere Funktion gibt, die verhindert, dass Matches wie diese automatisch generiert werden. Es gibt also wirklich keinen Grund, sich über dieses Problem Gedanken zu machen. (Wenn Sie möchten, können Sie die FindMatches
-Funktion auch früher aufrufen.)
4. Konsolidierung der Checks
Zu diesem Zeitpunkt haben wir ein ziemlich starkes Matching-System, aber das Problem ist, dass unser Code redundant ist. Derzeit haben wir zwei verschiedene Funktionen, die prüfen, ob es einen passenden Nachbarn gibt, und der einzige Unterschied zwischen ihnen besteht darin, dass eine vertikal und die andere horizontal prüft.
Da die kostenlose Version von Construct 2 die Anzahl der Events begrenzt, ist dies definitiv eine Verschwendung. Um dies zu lösen, werden wir eine neue Version der Funktion erstellen, die beide Überprüfungen durchführen kann.
Wenn Sie sich die Funktion ansehen, werden Sie feststellen, dass der einzige Unterschied zwischen den beiden Versionen darin besteht, dass eine Block.Width + 2
zur x-Position des Blocks und die andere zur y-Position des Bock hinzufügt. Das Hindernis, das wir überwinden müssen, um dies zu einer einzelnen Funktion zu machen, besteht darin, der Funktion die Möglichkeit zu geben, Block.Width + 2
nur zu X
oder nur zu Y
hinzuzufügen, ohne eine If
-Anweisung oder mehrere Funktionen zu verwenden, da diese mehr erfordern Auszuführende Events.
Meine Lösung hierfür ist nicht sehr komplex, aber es wird einfacher zu verstehen sein, wenn wir sehen, dass es zusammenkommt, also werden wir es implementieren und ich werde erklären, wie es funktioniert, sobald wir alles in Aktion sehen können.
- Löschen Sie das
CheckMatchesY
-Event. - Benennen Sie das
CheckMatchesX
-Event einfach inCheckMatches
um. - Im Funktionsaufruf für
CheckMatchesX
unter demFindMatches
-Event:- Ändern Sie den Funktionsaufruf für
CheckMatches
anstelle vonCheckMatchesX
. -
Parameter 3
hinzufügen.- Wert =
1
.
- Wert =
-
Parameter 4
hinzufügen.- Wert =
0
.
- Wert =
- Ändern Sie den Funktionsaufruf für
- Im Funktionsaufruf für
CheckMatchesY
unter demFindMatches
-Event:- Ändern Sie den Funktionsaufruf für
CheckMatches
anstelle vonCheckMatchesY
. -
Parameter 3
hinzufügen.- Wert = 0.
-
Parameter 4
hinzufügen.- Wert =
1
.
- Wert =
- Ändern Sie den Funktionsaufruf für
Wie ich bald erläutern werde, teilen diese hinzugefügten Parameter CheckMatches
mit, ob eine horizontale oder eine vertikale Prüfung durchgeführt wird. Wenn wir 1
für Parameter 3
und 0
für Parameter 4
einsenden, handelt es sich um eine horizontale Prüfung, und wenn wir 0
für Parameter 3
und 1
für Parameter 4
einsenden, handelt es sich um eine vertikale Prüfung.
Kehren Sie nun zur CheckMatches
-Funktion zurück und ändern Sie die Bedingungen und Aktionen so, dass sie folgendermaßen aussehen:
Event: Function > On function Name: "CheckMatches" Sub-Event: Condition: Block > Compare X X = Function.Param(0) + ((Block.Width+2)*Function.Param(3)) Condition: Block > Compare Y Y = Function.Param(1) + ((Block.Width+2)*Function.Param(4)) Condition: Block > Compare instance variable Color = Function.Param(2) Action: Block > Set Boolean IsMatched = True Action: Function > Call function Name: "CheckMatches" Parameter 0: Function.Param(0) + ((Block.Width+2)*Function.Param(3)) Parameter 1: Function.Param(1) + ((Block.Width+2)*Function.Param(4)) Parameter 2: Function.Param(2) Parameter 3: Function.Param(3) Parameter 4: Function.Param(4) Sub-Event: System > Compare Variable NumMatchesFound >= 3 Action: Block > Set Boolean IsMatched = True
So sollte Ihr FindMatches
- und CheckMatches
-Code jetzt aussehen:



Wie funktioniert das?
Was macht diese neue Version der Funktion eigentlich?
Nun, wenn Sie CheckMatches
aufrufen, senden Sie jetzt zwei weitere Parameter und anstatt Block.Width + 2
entweder zur x- oder zur y-Position hinzuzufügen, wird (Block.Width + 2) * Function.Param(3)
hinzugefügt ) zur x-Position und (Block.Width + 2) * Function.Param(4)
zur y-Position.
Da einer dieser beiden Parameter immer 1
und der andere immer 0
ist, bedeutet dies, dass entweder die x- oder die y-Position geändert wird - niemals beide!
Wenn wir zum Beispiel 1
für Parameter 3
und 0
für Parameter 4
übergeben, addiert es (Block.Width + 2) * 1
, was einfach Block.Width + 2
ist, zur x-Position und (Block.Width + 2) * 0
, also 0
, zur y-Position.
Hier ist ein kurzes Beispiel, um zu zeigen, was ich meine und wie die Position des Blocks berechnet wird, an dem nach Matches gesucht wird. Angenommen, in diesem Beispiel befindet sich der ursprüngliche Block bei (200, 200)
und die Blöcke haben eine Breite von 40
. Wenn wir also die Position des benachbarten vertikalen Blocks ermitteln möchten, würden die Formeln folgendermaßen funktionieren:
X = 200 + ((Block.Width + 2)*0) = 200 + (40 + 2)*0 = 200 + 0 = 200
Y = 200 + ((Block.Width + 2)*1) = 200 + (40 + 2)*1 = 200 + 42 = 242
Wenn wir die Position des benachbarten horizontalen Blocks erhalten wollten, würden die Formeln folgendermaßen funktionieren:
X = 200 + ((Block.Width + 2)*1) = 200 + (40 + 2)*1 = 200 + 42 = 242
Y = 200 + ((Block.Width + 2)*0) = 200 + (40 + 2)*0 = 200 + 0 = 200
Wenn Sie das Spiel jetzt ausführen, sollten Sie sehen, dass das Match-System immer noch so funktioniert, wie es ursprünglich war, aber aus unserer Sicht ist es tatsächlich ein besseres System.
Abschluss
Zu diesem Zeitpunkt ist unsere Match-Erkennungsfunktion noch unvollständig, aber wir haben bereits viel in diesem Tutorial getan, und ich denke, es ist wichtig, all dies zu berücksichtigen, bevor wir etwas anderes hinzufügen. In diesem Sinne werde ich diesen Artikel hier beenden. Schauen Sie sich die Demo in ihrer aktuellen Form an.
Im nächsten Artikel werden wir ein Punktesystem hinzufügen, das Matching-System verbessern und "Schwerkraft" hinzufügen, so dass die Blöcke fallen, wenn Blöcke darunter entfernt werden.
Wenn Sie sich einen Vorsprung für den nächsten Artikel verschaffen möchten, nehmen Sie sich etwas Zeit, um zu überlegen, wie Sie erkennen würden, wenn sich unter einem Block ein leerer Bereich befindet. Schauen Sie sich die Funktion Block > Is Overlapping at Offset
, um sich inspirieren zu lassen!