Cet article décrit le processus de création d'un jeu simple d'entraînement de mémoire que j'apprécie vraiment. En plus d'être bon en soi, vous en apprendrez un peu plus sur les classes et les protocoles Swift au fur et à mesure. Mais avant de commencer, comprenons le jeu lui-même.
Nous rappelons:pour tous les lecteurs de "Habr" - une remise de 10 000 roubles lors de l'inscription à n'importe quel cours Skillbox en utilisant le code promotionnel "Habr".
Le jeu commence par une démonstration d'un jeu de cartes. Ils se couchent face contre terre (respectivement, image vers le bas). Lorsque vous cliquez sur l'un d'entre eux, l'image s'ouvre pendant quelques secondes.
La tâche du joueur est de trouver toutes les cartes avec les mêmes images. Si, après avoir ouvert la première carte, vous retournez la seconde et que les images correspondent, les deux cartes restent ouvertes. Si elles ne correspondent pas, les cartes sont refermées. Le but est de tout ouvrir.
Structure du projet
Pour créer une version simple de ce jeu, vous avez besoin des composants suivants :
Un contrôleur : GameController.swift.
Une vue : CardCell.swift.
Deux modèles : MemoryGame.swift et Card.swift.
Main.storyboard pour garantir que l’ensemble des composants est disponible.
Nous commençons par l’élément le plus simple du jeu, les cartes.
Carte.swift
Le modèle de carte aura trois propriétés : un identifiant pour identifier chacun d'entre eux, une variable booléenne affichée pour spécifier l'état de la carte (cachée ou ouverte) et une artworkURL pour les images sur les cartes.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Vous aurez également besoin de ces méthodes pour contrôler l'interaction des utilisateurs avec les cartes :
Méthode d'affichage d'une image sur une carte. Ici, nous réinitialisons toutes les propriétés par défaut. Pour l'identifiant, nous générons un identifiant aléatoire en appelant NSUUIS().uuidString.
Méthode pour créer une copie de chaque carte - afin d'en obtenir un plus grand nombre d'identiques. Cette méthode renverra une carte avec des valeurs similaires.
Le deuxième modèle est MemoryGame, ici nous définissons une grille 4*4. Le modèle aura des propriétés telles que Cards (un tableau de cartes sur une grille), un tableau CardsShown avec des cartes déjà ouvertes et une variable booléenne isPlaying pour suivre l'état du jeu.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Nous devons également développer des méthodes pour contrôler l’interaction des utilisateurs avec la grille.
Une méthode qui mélange les cartes dans une grille.
Méthode pour créer un nouveau jeu. Ici, nous appelons la première méthode pour démarrer la mise en page initiale et initialiser la variable isPlaying à true.
Cette méthode lit le dernier élément du tableau **cardsShown** et renvoie la carte qui ne correspond pas.
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 et GameController.swift
Main.storyboard ressemble à ceci :
Initialement, vous devez définir le nouveau jeu comme viewDidLoad dans le contrôleur, y compris les images de la grille. Dans le jeu, tout cela sera représenté par 4*4 collectionView. Si vous n'êtes pas encore familier avec collectionView, le voici vous pouvez obtenir les informations dont vous avez besoin.
Nous allons configurer le GameController comme contrôleur racine de l'application. Le GameController aura une collectionView que nous référencerons comme un IBOutlet. Une autre référence concerne le bouton IBAction onStartGame(), il s'agit d'un UIButton, vous pouvez le voir dans le storyboard appelé PLAY.
Un peu sur l'implémentation des contrôleurs :
Tout d'abord, nous initialisons deux objets principaux - la grille : game = MemoryGame() et un jeu de cartes : cards = [Card]().
Nous définissons les variables initiales comme viewDidLoad, c'est la première méthode appelée pendant l'exécution du jeu.
collectionView est défini sur caché car toutes les cartes sont masquées jusqu'à ce que l'utilisateur appuie sur PLAY.
Dès que nous appuyons sur PLAY, la section onStartGame IBAction démarre et nous définissons la propriété collectionView isHidden sur false afin que les cartes puissent devenir visibles.
Chaque fois que l'utilisateur sélectionne une carte, la méthode didSelectItemAt est appelée. Dans la méthode, nous appelons didSelectCard pour implémenter la logique principale du jeu.
Parlons maintenant un peu des protocoles importants.
Protocoles
Travailler avec des protocoles est au cœur de la programmation Swift. Les protocoles offrent la possibilité de définir des règles pour une classe, une structure ou une énumération. Ce principe permet d'écrire du code modulaire et extensible. En fait, il s'agit d'un modèle que nous implémentons déjà pour collectionView dans GameController. Créons maintenant notre propre version. La syntaxe ressemblera à ceci :
protocol MemoryGameProtocol {
//protocol definition goes here
}
Nous savons qu'un protocole nous permet de définir des règles ou des instructions pour implémenter une classe, réfléchissons donc à ce qu'elles devraient être. Il vous en faut quatre au total.
Début du jeu : memoryGameDidStart.
Vous devez retourner la carte face cachée : memoryGameShowCards.
Vous devez retourner la carte face cachée : memoryGameHideCards.
Fin du jeu : memoryGameDidEnd.
Les quatre méthodes peuvent être implémentées pour la classe principale, GameController.
mémoireJeuDidStart
Lorsque cette méthode est exécutée, le jeu devrait démarrer (l'utilisateur appuie sur PLAY). Ici, nous allons simplement recharger le contenu en appelant collectionView.reloadData(), ce qui mélangera les cartes.
Nous appelons cette méthode depuis collectionSDViewSelectItemAt. Tout d'abord, il montre la carte sélectionnée. Vérifie ensuite s'il y a une carte sans correspondance dans le tableau CardsShown (si le nombre de CardsShown est impair). S'il y en a une, la carte sélectionnée lui est comparée. Si les images sont les mêmes, les deux cartes sont ajoutées aux cartes affichées et restent face visible. Si elle est différente, la carte laisse les cartes affichées et les deux sont retournées face cachée.
mémoireGameHideCards
Si les cartes ne correspondent pas, cette méthode est appelée et les images des cartes sont masquées.
montré = faux.
mémoireJeuDidEnd
Lorsque cette méthode est appelée, cela signifie que toutes les cartes sont déjà révélées et se trouvent dans la liste cardsShown : cardsShown.count = cards.count, donc la partie est terminée. La méthode est appelée spécifiquement après que nous ayons appelé endGame() pour définir la variable isPlaying sur false, après quoi le message de fin de jeu s'affiche. alertController est également utilisé comme indicateur pour le contrôleur. viewDidDislessly est appelé et le jeu est réinitialisé.
Voici à quoi tout cela ressemble dans GameController :
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()
}
}
En fait, c'est tout. Vous pouvez utiliser ce projet pour créer votre propre version du jeu.