Dieser Artikel beschreibt den Prozess der Erstellung eines einfachen Gedächtnistrainingsspiels, das mir wirklich gefällt. Abgesehen davon, dass es an sich gut ist, erfahren Sie im Laufe der Zeit auch etwas mehr über Swift-Klassen und -Protokolle. Aber bevor wir beginnen, wollen wir das Spiel selbst verstehen.
Erinnerung:für alle Leser von „Habr“ – ein Rabatt von 10 Rubel bei der Anmeldung zu einem beliebigen Skillbox-Kurs mit dem Aktionscode „Habr“.
Das Spiel beginnt mit der Demonstration eines Kartensatzes. Sie liegen mit dem Gesicht nach unten (bzw. mit dem Bild nach unten). Wenn Sie auf eines klicken, wird das Bild für einige Sekunden geöffnet.
Die Aufgabe des Spielers besteht darin, alle Karten mit den gleichen Bildern zu finden. Wenn man nach dem Öffnen der ersten Karte die zweite umdreht und die Bilder übereinstimmen, bleiben beide Karten offen. Bei Nichtübereinstimmung werden die Karten wieder geschlossen. Ziel ist es, alles zu öffnen.
Projektstruktur
Um eine einfache Version dieses Spiels zu erstellen, benötigen Sie folgende Komponenten:
Ein Controller: GameController.swift.
Eine Ansicht: CardCell.swift.
Zwei Modelle: MemoryGame.swift und Card.swift.
Main.storyboard um sicherzustellen, dass der gesamte Satz an Komponenten verfügbar ist.
Wir beginnen mit der einfachsten Komponente des Spiels, den Karten.
Card.swift
Das Kartenmodell verfügt über drei Eigenschaften: id zur Identifizierung jedes einzelnen, eine boolesche Variable, die angezeigt wird, um den Status der Karte (versteckt oder offen) anzugeben, und ArtworkURL für die Bilder auf den Karten.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Sie benötigen außerdem diese Methoden, um die Benutzerinteraktion mit Karten zu steuern:
Verfahren zum Anzeigen eines Bildes auf einer Karte. Hier setzen wir alle Eigenschaften auf die Standardeinstellungen zurück. Für die ID generieren wir eine zufällige ID, indem wir NSUUIS().uuidString aufrufen.
Methode zum Erstellen einer Kopie jeder Karte - um eine größere Anzahl identischer Exemplare zu erhalten. Diese Methode gibt eine Karte mit ähnlichen Werten zurück.
Das zweite Modell ist MemoryGame, hier legen wir ein 4*4-Raster fest. Das Modell verfügt über Eigenschaften wie „Cards“ (eine Anordnung von Karten in einem Raster), ein „cardsShown“-Array mit bereits geöffneten Karten und eine boolesche Variable „isPlaying“, um den Status des Spiels zu verfolgen.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Wir müssen auch Methoden entwickeln, um die Benutzerinteraktion mit dem Grid zu steuern.
Methode zum Erstellen eines neuen Spiels. Hier rufen wir die erste Methode auf, um das anfängliche Layout zu starten und die Variable isPlaying auf true zu initialisieren.
Diese Methode liest das letzte Element im Array **cardsShown** und gibt die nicht passende Karte zurück.
func didSelectCard(_ card: Card?) {
guard let card = card else { return }
if unmatchedCardShown() {
let unmatched = unmatchedCard()!
if card.equals(unmatched) {
cardsShown.append(card)
} else {
let secondCard = cardsShown.removeLast()
}
} else {
cardsShown.append(card)
}
if cardsShown.count == cards.count {
endGame()
}
}
Main.storyboard und GameController.swift
Main.storyboard sieht in etwa so aus:
Zunächst müssen Sie das neue Spiel im Controller als viewDidLoad festlegen, einschließlich der Bilder für das Raster. Im Spiel wird all dies durch 4*4 CollectionView dargestellt. Wenn Sie mit „collectionView“ noch nicht vertraut sind, finden Sie es hier Sie können die Informationen erhalten, die Sie benötigen.
Wir werden den GameController als Root-Controller der Anwendung konfigurieren. Der GameController verfügt über eine CollectionView, auf die wir als IBOutlet verweisen. Ein weiterer Verweis bezieht sich auf die IBAction onStartGame()-Schaltfläche. Dies ist eine UIButton, Sie können sie im Storyboard mit dem Namen PLAY sehen.
Ein wenig über die Implementierung von Controllern:
Zuerst initialisieren wir zwei Hauptobjekte – das Raster: game = MemoryGame() und einen Satz Karten: Cards = [Card]().
Wir setzen die Anfangsvariablen auf viewDidLoad, dies ist die erste Methode, die aufgerufen wird, während das Spiel läuft.
„collectionView“ ist auf „hidden“ gesetzt, da alle Karten ausgeblendet sind, bis der Benutzer auf „PLAY“ drückt.
Sobald wir PLAY drücken, startet der onStartGame IBAction-Abschnitt und wir setzen die Eigenschaft „collectionView isHidden“ auf „false“, damit die Karten sichtbar werden können.
Jedes Mal, wenn der Benutzer eine Karte auswählt, wird die Methode didSelectItemAt aufgerufen. In der Methode rufen wir didSelectCard auf, um die Hauptspiellogik zu implementieren.
Hier ist die endgültige GameController-Implementierung:
Lassen Sie uns nun ein wenig über die wichtigen Protokolle sprechen.
Protokolle
Die Arbeit mit Protokollen ist der Kern der Swift-Programmierung. Protokolle bieten die Möglichkeit, Regeln für eine Klasse, Struktur oder Aufzählung zu definieren. Dieses Prinzip ermöglicht es Ihnen, modularen und erweiterbaren Code zu schreiben. Tatsächlich ist dies ein Muster, das wir bereits für CollectionView in GameController implementieren. Jetzt erstellen wir unsere eigene Version. Die Syntax sieht folgendermaßen aus:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Wir wissen, dass wir mit einem Protokoll Regeln oder Anweisungen für die Implementierung einer Klasse definieren können. Denken wir also darüber nach, wie diese aussehen sollten. Sie benötigen insgesamt vier.
Spielstart: MemoryGameDidStart.
Sie müssen die Karte umdrehen: MemoryGameShowCards.
Sie müssen die Karte umdrehen: MemoryGameHideCards.
Spielende: MemoryGameDidEnd.
Alle vier Methoden können für die Hauptklasse GameController implementiert werden.
MemoryGameDidStart
Wenn diese Methode ausgeführt wird, sollte das Spiel starten (der Benutzer drückt PLAY). Hier laden wir einfach den Inhalt neu, indem wir „collectionView.reloadData()“ aufrufen, wodurch die Karten gemischt werden.
Wir rufen diese Methode von „collectionSDViewSelectItemAt“ auf. Zuerst wird die ausgewählte Karte angezeigt. Anschließend wird überprüft, ob sich im Array „cardsShown“ eine nicht übereinstimmende Karte befindet (wenn die Anzahl der „cardsShown“ ungerade ist). Ist eine vorhanden, wird die ausgewählte Karte damit verglichen. Sind die Bilder gleich, werden beide Karten zu den angezeigten Karten hinzugefügt und bleiben offen liegen. Wenn sie unterschiedlich sind, werden die Karten nicht angezeigt und beide werden umgedreht.
MemoryGameHideCards
Wenn die Karten nicht übereinstimmen, wird diese Methode aufgerufen und die Kartenbilder werden ausgeblendet.
angezeigt = falsch.
MemoryGameDidEnd
Wenn diese Methode aufgerufen wird, bedeutet dies, dass alle Karten bereits aufgedeckt sind und sich in der CardsShown-Liste befinden: CardsShown.count = Cards.count, das Spiel ist also beendet. Die Methode wird insbesondere aufgerufen, nachdem wir endGame() aufgerufen haben, um die Variable isPlaying auf false zu setzen, woraufhin die Meldung über das Ende des Spiels angezeigt wird. AlertController wird auch als Indikator für den Controller verwendet. viewDidDisappear wird aufgerufen und das Spiel wird zurückgesetzt.
So sieht alles im GameController aus:
extension GameController: MemoryGameProtocol {
func memoryGameDidStart(_ game: MemoryGame) {
collectionView.reloadData()
}
func memoryGame(_ game: MemoryGame, showCards cards: [Card]) {
for card in cards {
guard let index = game.indexForCard(card)
else { continue
}
let cell = collectionView.cellForItem(
at: IndexPath(item: index, section:0)
) as! CardCell
cell.showCard(true, animted: true)
}
}
func memoryGame(_ game: MemoryGame, hideCards cards: [Card]) {
for card in cards {
guard let index = game.indexForCard(card)
else { continue
}
let cell = collectionView.cellForItem(
at: IndexPath(item: index, section:0)
) as! CardCell
cell.showCard(false, animted: true)
}
}
func memoryGameDidEnd(_ game: MemoryGame) {
let alertController = UIAlertController(
title: defaultAlertTitle,
message: defaultAlertMessage,
preferredStyle: .alert
)
let cancelAction = UIAlertAction(
title: "Nah", style: .cancel) {
[weak self] (action) in
self?.collectionView.isHidden = true
}
let playAgainAction = UIAlertAction(
title: "Dale!", style: .default) {
[weak self] (action) in
self?.collectionView.isHidden = true
self?.resetGame()
}
alertController.addAction(cancelAction)
alertController.addAction(playAgainAction)
self.present(alertController, animated: true) { }
resetGame()
}
}
Eigentlich ist das alles. Mit diesem Projekt können Sie Ihre eigene Version des Spiels erstellen.