
Cet article décrit le processus de création d'un jeu d'entraînement à la mémoire simple que j'aime vraiment. En plus d'être bon en soi, vous en apprendrez un peu plus sur les classes et les protocoles Swift pendant le travail. Mais avant de commencer, découvrons le jeu lui-même.
Nous vous rappelons: pour tous les lecteurs de «Habr» - une remise de 10 000 roubles lors de l'inscription à un cours Skillbox en utilisant le code promo «Habr».
Skillbox recommande: Le cours éducatif en ligne "Profession Java-developer" .
Comment jouer à la carte mémoire
Le jeu commence par une démonstration d'un jeu de cartes. Ils se couchent «chemise» (respectivement, face vers le bas). Lorsque vous cliquez sur l'un d'eux, une 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. S'ils ne correspondent pas, les cartes sont à nouveau fermées. La tâche consiste à 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 afin que l'ensemble des composants soit disponible.
Nous commençons avec le composant le plus simple du jeu, la carte.
Card.swiftLe modèle de carte aura trois propriétés: id pour identifier chacune, une variable logique affichée pour clarifier le statut de la carte (cachée ou ouverte) et 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 de l'utilisateur 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 id, générez un identifiant aléatoire en appelant NSUUIS (). UuidString.
init(image: UIImage) { self.id = NSUUID().uuidString self.shown = false self.artworkURL = image }
Méthode de comparaison des cartes d'identité. func equals(_ card: Card) -> Bool { return (card.id == id) }
La méthode pour créer une copie de chaque carte est d'obtenir un plus grand nombre de
cartes identiques. Cette méthode retournera une carte avec des valeurs similaires.
func copy() -> Card { return Card(card: self) } init(card: Card) { self.id = card.id self.shown = card.shown self.artworkURL = card.artworkURL }
Et une autre méthode est nécessaire pour mélanger les cartes au début. Nous en ferons une extension de la classe Array.
extension Array { mutating func shuffle() { for _ in 0...self.count { sort { (_,_) in arc4random() < arc4random() } } } }
Et voici l'implémentation du code pour le modèle Card avec toutes les propriétés et méthodes.
class Card { var id: String var shown: Bool = false var artworkURL: UIImage! static var allCards = [Card]() init(card: Card) { self.id = card.id self.shown = card.shown self.artworkURL = card.artworkURL } init(image: UIImage) { self.id = NSUUID().uuidString self.shown = false self.artworkURL = image } func equals(_ card: Card) -> Bool { return (card.id == id) } func copy() -> Card { return Card(card: self) } } extension Array { mutating func shuffle() { for _ in 0...self.count { sort { (_,_) in arc4random() < arc4random() } } } }
Allez-y.
Le deuxième modèle est MemoryGame, nous définissons ici la grille 4 * 4. Le modèle aura des propriétés telles que des cartes (un tableau de cartes sur la grille), un tableau cardsShown avec des cartes déjà ouvertes et le booléen 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. func shuffleCards(cards:[Card]) -> [Card] { var randomCards = cards randomCards.shuffle() return randomCards }
Méthode pour créer un nouveau jeu. Ici, nous appelons la première méthode pour démarrer la disposition initiale et initialiser la variable isPlaying comme vraie.
func newGame(cardsArray:[Card]) -> [Card] { cards = shuffleCards(cards: cardsArray) isPlaying = true return cards }
Si nous voulons redémarrer le jeu, nous définissons la variable isPlaying sur false et supprimons la disposition initiale des cartes.
func restartGame() { isPlaying = false cards.removeAll() cardsShown.removeAll() }
Méthode de vérification des cartes pressées. Plus d'informations à ce sujet plus tard.
func cardAtIndex(_ index: Int) -> Card? { if cards.count > index { return cards[index] } else { return nil } }
Une méthode qui renvoie la position d'une carte spécifique. func indexForCard(_ card: Card) -> Int? { for index in 0...cards.count-1 { if card === cards[index] { return index } } return nil }
Vérification de la conformité de la carte sélectionnée avec la norme
func unmatchedCardShown() -> Bool { return cardsShown.count % 2 != 0 }
Cette méthode lit le dernier élément du tableau ** cardsShown ** et renvoie une carte inappropriée.
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, dans le contrôleur, vous devez installer un nouveau jeu comme viewDidLoad, y compris des images pour la grille. Dans le jeu, tout cela sera représenté par 4 * 4 collectionView. Si vous n'êtes pas familier avec collectionView,
vous pouvez obtenir ici
les informations nécessaires .
Nous allons configurer GameController comme contrôleur racine de l'application. Il y aura une collectionView dans GameController, que nous référencerons comme IBOutlet. Un autre lien est le bouton IBAction onStartGame (), c'est UIButton, vous pouvez le voir dans le storyboard appelé PLAY.
Un peu sur la mise en œuvre des contrôleurs:
- Tout d'abord, nous initialisons les deux objets principaux - la grille (jeu): jeu = MemoryGame (), et sur le jeu de cartes: cards = [Carte] ().
- Définissez les variables initiales comme viewDidLoad, c'est la première méthode qui est appelée pendant le jeu.
- définissez collectionView comme masqué, 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 qu'un utilisateur sélectionne une carte, la méthode didSelectItemAt est appelée. Dans la méthode, nous appelons didSelectCard pour implémenter la logique de base du jeu.
Voici l'implémentation finale de GameController:
class GameController: UIViewController { @IBOutlet weak var collectionView: UICollectionView! let game = MemoryGame() var cards = [Card]() override func viewDidLoad() { super.viewDidLoad() game.delegate = self collectionView.dataSource = self collectionView.delegate = self collectionView.isHidden = true APIClient.shared.getCardImages { (cardsArray, error) in if let _ = error {
Arrêtons-nous maintenant sur certains protocoles importants.
Protocoles
Travailler avec des protocoles est le fondement de la programmation Swift. Les protocoles permettent de définir des règles pour une classe, une structure ou une énumération. Ce principe vous permet d'écrire du code modulaire et extensible. Il s'agit en fait d'un modèle que nous implémentons déjà pour collectionView dans GameController. Faisons maintenant notre propre version. La syntaxe ressemblera à ceci:
protocol MemoryGameProtocol {
Nous savons qu'un protocole vous permet de définir des règles ou des instructions pour implémenter une classe, alors réfléchissons à ce qu'elles devraient être. Seulement quatre sont nécessaires.
- Début du jeu: memoryGameDidStart.
- Besoin de retourner la carte face cachée: memoryGameShowCards.
- Besoin de retourner la carte face cachée: memoryGameHideCards.
- Fin du jeu: memoryGameDidEnd.
Nous implémentons les quatre méthodes pour la classe principale, et c'est GameController.
memoryGameDidStart
Lorsque cette méthode est lancée, le jeu devrait commencer (l'utilisateur appuie sur PLAY). Ici, nous rechargeons simplement le contenu en appelant collectionView.reloadData (), ce qui entraînera un brassage des cartes.
func memoryGameDidStart(_ game: MemoryGame) { collectionView.reloadData() }
memoryGameShowCards
Appelez cette méthode à partir de collectionSDViewSelectItemAt. Tout d'abord, il montre la carte sélectionnée. Ensuite, il vérifie s'il y a une carte inégalée dans le tableau cardsShown (si le nombre de cardsShown est impair). S'il y en a une, la carte sélectionnée est comparée avec elle. Si les images sont identiques, les deux cartes sont ajoutées aux cartes affichées et restent ouvertes. Si elle est différente, la carte laisse les cartes montrées, et les deux retournent à l'envers.
memoryGameHideCards
Si les cartes ne correspondent pas, cette méthode est appelée et les images des cartes sont masquées.
montré = faux.
memoryGameDidEnd
Lorsque cette méthode est appelée, cela signifie que toutes les cartes sont déjà ouvertes et se trouvent dans la liste cardsShown: cardsShown.count = cards.count, donc le jeu est terminé. La méthode est appelée spécifiquement après que nous ayons appelé endGame () pour définir isPlaying var sur false, après quoi un message sur la fin du jeu s'affiche. AlertController est également utilisé comme indicateur pour le contrôleur. ViewDidDisappear 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() } }

C'est tout. Vous pouvez utiliser ce projet pour créer votre propre version du jeu.
Bon codage!
Skillbox recommande: