Prototypage rapide et interactif avec les terrains de jeu Xcode

Ce que vous allez créer

introduction

Depuis leur introduction dans Xcode 6 aux côtés de Swift, jusqu'à leur itération actuelle dans Xcode 7.3.1, les terrains de jeu ont parcouru un long chemin. Avec de nouvelles fonctionnalités et une meilleure stabilité, ils deviennent un outil viable pour le prototypage rapide ou le piratage rapide d’une preuve de concept..

En tant que développeur, vous avez parfois un souffle d'inspiration sous la forme d'une idée intéressante pour une application et vous souhaitez coder rapidement un prototype qui représente l'essence même de votre idée. Ou vous voulez simplement vérifier votre compréhension de la façon dont une partie du code UIKit se comportera. Si vous êtes comme moi, vous préféreriez éviter les tracas et la surcharge mentale liés à la création d'un projet Xcode et à la gestion d'une multitude de facteurs, tels que les types et résolutions de périphériques et les paramètres de construction. Ces décisions peuvent être reportées jusqu'à ce que vous ayez décidé que l'idée de base mérite d'être poursuivie..

Dans ce didacticiel, nous créons un jeu de mémoire à base de cartes, le tout dans les limites d’un terrain de jeu. C'est un jeu commun et bien connu, il n'y a donc aucun crédit pour l'originalité. Le jeu consiste en huit paires de cartes identiques (soit un total de 16 cartes) placées face cachée dans une grille 4x4..

Le joueur doit retourner deux cartes dont les faces sont brièvement révélées, puis rapidement retournées. L’objectif du jeu est que le joueur essaie de se rappeler les positions des cartes et de découvrir des paires identiques, qui sont ensuite retirées du jeu. Le jeu est terminé lorsque la grille est effacée.

Le jeu est tactile et intègre de simples animations de vue. Vous apprendrez comment modifier votre application et voir le résultat de vos modifications en direct.

1. Commencer

Lancez Xcode et sélectionnez Nouveau> Terrain de jeu… de Xcode Fichier menu. Donnez un nom à la cour, par exemple MemoryGameXCPTut, ensemble Plate-forme à iOS, et sauver le terrain de jeu. J'utilise Xcode 7.3.1 pour ce tutoriel.

Trouver votre chemin autour du terrain de jeu

Passons un peu de temps à nous familiariser avec l'interface du terrain de jeu. N'hésitez pas à parcourir cette section si vous connaissez déjà les terrains de jeux.

Un terrain de jeu peut avoir plusieurs pages, chacune associée à sa propre vue en direct et à ses propres dossiers sources / ressources. Nous n'utiliserons pas plusieurs pages dans ce tutoriel. Les terrains de jeu prennent en charge le formatage des balises qui vous permet d’ajouter du texte enrichi à un terrain de jeu et de créer un lien entre les pages de terrain de jeu..

La première chose que vous voyez après la création d’un terrain de jeu est l’éditeur de source. C'est là que vous écrivez du code, ce qui a un effet immédiat sur la vue en direct. L’un des moyens de faire basculer l’aspect (dé) apparence du Navigateur de projet utilise le raccourci Commande-0. dans le Navigateur de projet, vous pouvez voir deux dossiers, Sources et Ressources.

Sources

dans le Sources dossier, vous pouvez ajouter du code auxiliaire dans un ou plusieurs fichiers Swift, tels que des classes personnalisées, des contrôleurs de vue et des vues. Même si la majeure partie du code définissant la logique de votre prototype y figure, il est auxiliaire en ce sens qu'il est dissimulé à l'arrière-plan lorsque vous visualisez votre application en direct..

L’avantage de mettre le code auxiliaire dans le Sources dossier est qu’il est automatiquement compilé chaque fois que vous modifiez et enregistrez le fichier. De cette façon, vous obtenez un retour plus rapide dans la vue en direct à partir des modifications apportées dans la cour. De retour dans la cour de récréation, vous pouvez accéder Publique propriétés et méthodes que vous exposez dans le code auxiliaire affectant le comportement de votre application.

Ressources

Vous pouvez ajouter des ressources externes, telles que des images, dans Ressources dossier.

Dans ce didacticiel, vous devez souvent passer d’un fichier Swift créé dans le répertoire Sources dossier et le fichier de jeu (techniquement aussi un fichier Swift, sauf que vous ne vous y référerez pas par son nom de fichier). Nous utilisons également le Assistant rédacteur dans le tutoriel, l'afficher Chronologie, pour afficher la sortie en direct côte à côte avec le code de la cour de récréation. Toutes les modifications que vous apportez dans la cour de récréation sont immédiatement reflétées (en quelques secondes) dans la sortie en direct. Vous pouvez également interagir avec la vue en direct et ses éléments d'interface utilisateur. Pour vous assurer de pouvoir faire tout cela, jetez un coup d’œil à la figure ci-dessous..

Correspondant aux chiffres verts que j'ai ajoutés à la figure:

  1. Ce bouton cache le Assistant rédacteur de sorte que seul l'éditeur principal est visible.
  2. Ce bouton révèle le Assistant rédacteur. le Assistant rédacteur est visible à droite de l'éditeur principal. Cet éditeur peut aider en nous montrant des fichiers pertinents, tels que la contrepartie du fichier dans l'éditeur principal..
  3. De gauche à droite, ces deux boutons sont respectivement utilisés pour changer l’apparence de Navigateur de projet et la console de débogage. Dans la console, nous pouvons inspecter la sortie des instructions d'impression, entre autres.
  4. le barre de saut en haut de l'éditeur principal peut également être utilisé pour naviguer vers un fichier particulier. En cliquant deux fois sur le nom du projet, vous revenez dans la cour de récréation. Vous pouvez également utiliser le Navigateur de projet.

Parfois, lorsque vous regardez le terrain de jeu, vous devez vous assurer que le Assistant rédacteur affiche le Chronologie au lieu d'un autre fichier. La figure ci-dessous montre comment procéder. dans le Assistant rédacteur, sélectionner Chronologie, la contrepartie du terrain de jeu, au lieu de Manuel, qui vous permet d'afficher n'importe quel fichier dans le Assistant rédacteur.

Lorsque vous éditez un fichier source à partir du Sources dossier, comme son homologue, le Assistant rédacteur affiche l'interface de votre code, c'est-à-dire les déclarations et les prototypes de fonctions sans leur implémentation. Je préfère cacher le Assistant rédacteur quand je travaille sur un fichier dans le Sources dossier et exposer uniquement le Assistant rédacteur dans l'aire de jeu pour voir la vue en direct.

Pour accéder aux capacités spéciales des terrains de jeu, vous devez importer le module XCPlayground..

importer XCPlayground

Vous définissez le vue en direct propriété du page actuelle du XCPlaygroundPage objet à un objet qui se conforme à la  XCPlaygroundLiveViewable protocole. Cela peut être une classe personnalisée ou ce peut être un UIView ou UIViewController exemple.

Ajout de fichiers au dossier Sources / Ressources

J'ai ajouté quelques images avec lesquelles nous pouvons travailler dans ce tutoriel. Téléchargez les images, extrayez l’archive et ajoutez les images dans le dossier Images dossier à la Ressources dossier du terrain de jeu dans le Navigateur de projet.

Assurez-vous de ne faire glisser que les images afin que chaque fichier d’image réside dans le Ressources dossier, pas dans Ressources / Images.

Supprimez le code dans la cour de récréation. Faites un clic droit sur le Sources dossier et sélectionnez Nouveau fichier du menu. Définissez le nom du fichier sur Game.swift.

2. Classes et méthodes d'aide à la rédaction

Ajoutez le code suivant à Game.swift. Assurez-vous de sauvegarder le fichier après chaque ajout de code.

import UIKit import XCPlayground import GameplayKit // (1) extension publique UIImage // (2) commodité publique init? (couleur: UIColor, taille: CGSize = CGSize (largeur: 1, hauteur: 1)) let rect = CGRect ( origine: .zero, taille: taille) UIGraphicsBeginImageContextWithOptions (rect.size, false, 0.0) color.setFill () UIRectFill (rect) let image = UIGraphicsGetImageFromCurrentImageContext () UIGraphicsEndImageContext () guard let cgImage .init (CGImage: cgImage) let cardWidth = CGFloat (120) // (3) let cardHeight = CGFloat (141) Classe publique Card: UIImageView // (4) public let x: Int public let y: Int public init (image: UIImage ?, x: Int, y: Int) self.x = x self.y = y super.init (image: image) self.backgroundColor =. grayColor () self.layer.cornerRadius = 10.0 auto .userInteractionEnabled = true obligatoire public init (codeur aDecoder: NSCoder) fatalError ("init (codeur :) n'a pas été implémenté")

J'ai ajouté quelques commentaires numérotés pour expliquer certaines sections de la mise en œuvre:

  1. En plus de UIKit et XCPlayground, nous importons aussi GamePlayKit. Ce framework inclut une méthode pratique qui nous aidera à implémenter une méthode pour mélanger de manière aléatoire un tableau..
  2. Cette extension sur UIImage nous permet, avec l'aide de UIKit méthodes, pour faire des images avec une couleur unie de toute taille que nous voulons. Nous allons utiliser cela pour définir l'image de fond initiale des cartes à jouer.
  3. le cardHeight et largeur de la carte les constantes représentent les tailles d'image de la carte sur lesquelles nous allons calculer d'autres tailles.
  4. le Carte classe, héritant de UIImageView, représente une carte. Même si nous définissons quelques propriétés dans le Carte classe, le but principal de la création de cette classe est de nous aider à identifier et à parcourir les sous-vues qui correspondent aux cartes à jouer dans le jeu. Les cartes ont aussi des propriétés X et y se souvenir de leur position dans la grille.

3. Contrôleur de vue

Ajoutez le code suivant à Game.swift, immédiatement après le code précédent:

public class GameController: UIViewController // (1): variables publiques afin que nous puissions les manipuler dans le terrain de jeu. var var = CGFloat (20) / * didSet resetGrid () / public var backImage: UIImage = UIImage ( color: .redColor (), size: CGSize (width: largeur de la carte, hauteur: cardHeight))! // (2): propriétés calculées var viewWidth: CGFloat get return 4 * cardWidth + 5 * padding var viewHeight: CGFloat get return 4 * cardHeight + 5 * padding var shuffledNumbers = [Int] () // stocke les numéros de cartes mélangées // var firstCard: Card? // commenter plus tard public init () super.init (nibName: nil, bundle: nil) preferredContentSize = CGSize (width: viewWidth, height: viewHeight) shuffle () setupGrid () // annulez la mise en commentaire plus tard: // let tap = UITapGestureRecognizer (cible: self, action: #selector (GameController.handleTap (_ :))) // view.addGestureRecognizer (tap) init public requis (codeur aDecoder: NSCoder) fatalError ("init (codeur :) n'a pas été implémenté ") public override func loadView () view = UIView () view.backgroundColor = .blueColor () view.frame = CGRect (x: 0, y: 0, largeur: viewWidth, hauteur: viewHeight) // ( 3): Utilisation de l’API GameplayKit pour générer un remaniement du tableau [1, 1, 2, 2,…, 8, 8] func shuffle () let numbers = (1… 8) .flatMap [$ 0, $ 0] shuffledNumbers = GKRandomSource.sharedRandom (). arrayByShufflingObjectsInArray (nombres) en tant que! [Int] // (4): Conversion de la position de la carte sur la grille en index dans le tableau de numéros de cartes mélangées func cardNumberAt (x: Int, _ y: Int) -> Int assert (0 <= x && x < 4 && 0 <= y && y < 4) return shuffledNumbers[4 * x + y]  // (5): Position of card's center in superview func centerOfCardAt(x: Int, _ y: Int) -> CGPoint assert (0 <= x && x < 4 && 0 <= y && y < 4) let (w, h) = (cardWidth + padding, cardHeight + padding) return CGPoint( x: CGFloat(x) * w + w/2 + padding/2, y: CGFloat(y) * h + h/2 + padding/2)  // (6): setup the subviews func setupGrid()  for i in 0… <4  for j in 0… <4  let n = cardNumberAt(i, j) let card = Card(image: UIImage(named: String(n)), x: i, y: j) card.tag = n card.center = centerOfCardAt(i, j) view.addSubview(card)    // (7): reset grid /* func resetGrid()  view.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight) for v in view.subviews  if let card = v as? Card  card.center = centerOfCardAt(card.x, card.y)    */ override public func viewDidAppear(animated: Bool)  for v in view.subviews  if let card = v as? Card  // (8): failable casting UIView.transitionWithView( card, duration: 1.0, options: .TransitionFlipFromLeft, animations:  card.image = self.backImage , completion: nil)    
  1. Les deux propriétés, rembourrage et retour image, sont déclarés Publique afin que nous puissions y accéder plus tard dans la cour. Ils représentent l'espace vide entourant les cartes sur la grille et l'image affichée au dos de chaque carte, respectivement. Notez que des valeurs initiales ont été attribuées aux deux propriétés, représentant un remplissage de 20 et une couleur rouge unie pour l'image de la carte sans face. Vous pouvez ignorer le code commenté pour l'instant.
  2. Nous calculons la largeur et la hauteur souhaitées des vues à l'aide de propriétés calculées. Pour comprendre le viewWidth calcul, rappelez-vous qu’il y a quatre cartes dans chaque ligne et que nous devons également tenir compte du remplissage de chaque carte. La même idée s'applique à la voirHauteur calcul.
  3. Le code (1… 8) .flatMap [$ 0, $ 0] est un moyen concis de produire le tableau [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8]. Si vous n'êtes pas familier avec la programmation fonctionnelle, vous pouvez aussi écrire un pour-boucle pour générer le tableau. En utilisant des méthodes de la GamePlayKit cadre, nous mélangeons les nombres dans le tableau. Les numéros correspondent aux huit paires de cartes. Chaque numéro représente l’image de la carte du même nom (par exemple, une valeur de 1 dans shuffledArray Correspond à 1.png).
  4. Nous avons écrit une méthode qui mappe l’emplacement d’une carte sur la grille 4x4 à son emplacement dans le mélangéNombre tableau de longueur 16. Le facteur 4 dans le calcul arithmétique reflète le fait que nous avons quatre cartes par ligne.
  5. Nous avons également une méthode qui détermine la position d’une carte (son centre propriété) dans la grille en fonction des dimensions et du remplissage de la carte.
  6. le setupGrid () La méthode est appelée lors de l'initialisation du contrôleur de vue. Il expose le 4x4 Carte la grille. Il attribue également l’identité de chaque carte en fonction du mélangéNombre tableau et le stocke dans le étiquette propriété héritée de la classe de base de la carte, UIView. Dans la logique du jeu, on compare les étiquette valeurs pour déterminer si deux cartes correspondent ou non. Ce schéma de modélisation plutôt rudimentaire répond assez bien à nos besoins actuels.
  7. Ce morceau de code actuellement inutilisé nous aidera à repositionner les cartes au cas où le remplissage changerait. Rappelez-vous que nous avons déclaré la rembourrage propriété en tant que propriété publique afin que nous puissions y accéder dans l'aire de jeu.
  8. Le code en viewDidAppear (_ :) s'exécute immédiatement après que la vue du contrôleur de vue devienne visible. Nous parcourons les sous-vues de la vue et, si la sous-vue est une instance du Carte classe, (vérifié par le comme? opérateur de downcasting disponible) le corps de la si-déclaration définit la transition à effectuer. C’est là que nous allons changer l’image affichée sur les cartes, de l’image de dessin animé définissant le visage de chaque carte au (commun) retour image de toutes les cartes. Cette transition est accompagnée d'une animation de bascule de gauche à droite donnant l'apparence des cartes physiquement retournées. Si vous ne savez pas comment UIView les animations fonctionnent, cela peut sembler un peu étrange. Même si nous avons ajouté l'animation de chaque carte de manière séquentielle dans une boucle, les animations sont regroupées en une seule transaction d'animation et exécutées simultanément, c'est-à-dire que les cartes sont retournées ensemble..

Revisitez le terrain de jeu et remplacez le texte de l'éditeur par ce qui suit:

import XCPlayground import UIKit let gc = GameController () XCPlaygroundPage.currentPage.liveView = gc

Assurez-vous que la chronologie est visible. La vue du contrôleur de vue devrait prendre vie et nous montrer une grille de cartes 4x4 avec de jolis animaux de dessins animés qui se retournent pour nous montrer le dos des cartes. Pour l'instant, nous ne pouvons pas faire grand chose avec cette vue car nous n'y avons pas encore programmé d'interaction. Mais c'est définitivement un début.

4. Modification des variables dans le terrain de jeu

Changeons maintenant les faces arrières des cartes du rouge uni en une image, en particulier b.png dans le Ressources dossier. Ajouter la ligne suivante au bas de la cour.

gc.backImage = UIImage (nommé: "b")!

Après une seconde ou deux, vous constaterez que le verso des cartes est passé du rouge uni au dessin animé.

Essayons maintenant de modifier le rembourrage propriété, à laquelle nous avons attribué une valeur par défaut de 20 dans Game.swift. L'espace entre les cartes devrait donc augmenter. Ajoutez la ligne suivante au bas de la cour de récréation:

gc.padding = 75

Attendez que la vue en direct se rafraîchit et constatez que… rien n'a changé.

5. Un bref détour

Pour comprendre ce qui se passe, vous devez garder à l'esprit que les entités, telles que les contrôleurs de vue et leurs vues associées, ont un cycle de vie complexe. Nous allons nous concentrer sur ce dernier point, à savoir les points de vue. La création et la mise à jour de la vue d'un contrôleur de vue est un processus en plusieurs étapes. À des moments précis du cycle de vie de la vue, des notifications sont envoyées au UIViewController, l'informer de ce qui se passe. Plus important encore, le programmeur peut se connecter à ces notifications en insérant du code pour diriger et personnaliser ce processus..

le loadView () et viewDidAppear (_ :) les méthodes sont deux méthodes que nous avons utilisées pour s’intégrer au cycle de vie de la vue. Ce sujet est quelque peu impliqué et dépasse le cadre de la discussion, mais ce qui nous importe, c’est que le code dans la cour de récréation, après l’affectation du contrôleur de vue comme étant celui de la cour de récréation. vue en direct, est exécuté un certain temps entre l'appel à viewWillAppear (_ :) et l'appel à viewDidAppear (_ :). Vous pouvez le vérifier en modifiant certaines propriétés de la cour de récréation et en ajoutant des instructions d'impression à ces deux méthodes pour afficher la valeur de cette propriété..

La question de la valeur de rembourrage ne pas avoir l'effet visuel attendu, c'est qu'à ce moment-là, la vue et ses sous-vues sont déjà définies. Gardez à l'esprit que, chaque fois que vous modifiez le code, le terrain de jeu est réexécuté depuis le début. En ce sens, cette question n'est pas spécifique aux terrains de jeux. Même si vous développiez du code à exécuter sur le simulateur ou sur un périphérique physique, vous auriez souvent besoin d'écrire du code supplémentaire pour vous assurer que la modification de la valeur d'une propriété a l'effet souhaité sur l'apparence ou le contenu de la vue..

Vous pourriez vous demander pourquoi nous avons pu changer la valeur du retour image propriété et voir le résultat sans rien faire de spécial. Observez que le retour image la propriété est effectivement utilisée pour la première fois viewDidAppear (_ :), à quel moment il a déjà repris sa nouvelle valeur.

6. Observer les propriétés et passer à l'action

Notre façon de faire face à cette situation sera de surveiller les changements dans la valeur de rembourrage et redimensionnez / repositionnez la vue et les sous-vues. Heureusement, cela est facile à faire avec Swift observation de la propriété fonctionnalité. Commencez par décommenter le code pour le resetGrid () méthode en Game.swift:

// (7): reset grid func resetGrid () view.frame = CGRect (x: 0, y: 0, width: viewWidth, height: viewHeight) pour v dans view.subviews si let card = v as? Card card.center = centerOfCardAt (card.x, card.y)

Cette méthode recalcule la position du cadre de la vue et celle de chaque Carte objet basé sur les nouvelles valeurs de viewWidth et voirHauteur. Rappelez-vous que ces propriétés sont calculées en fonction de la valeur de rembourrage, qui vient d'être modifié.

Aussi, modifiez le code pour rembourrage utiliser le didSet observateur dont le corps, comme son nom l’indique, s’exécute chaque fois que nous définissons la valeur de rembourrage:

// (1): variables publiques afin que nous puissions les manipuler dans l'aire de jeu. Public var padding = CGFloat (20) didSet resetGrid ()

le resetGrid () La méthode entre en action et la vue est actualisée pour refléter le nouvel espacement. Vous pouvez le vérifier sur le terrain de jeu.

Il semble que nous ayons pu régler les problèmes assez facilement. En réalité, lorsque j’ai décidé pour la première fois, je voulais pouvoir interagir avec le rembourrage la propriété, je devais revenir en arrière et apporter des modifications au code dans Game.swift. Par exemple, je devais faire abstraction de la Carte calcul du centre dans une fonction séparée (centerOfCardAt (_: _ :)) pour (re) calculer proprement et indépendamment les positions des cartes chaque fois qu'elles doivent être disposées.

Faire des propriétés calculées pour viewWidth et voirHauteur également aidé. Ce genre de réécriture est une chose à laquelle vous devriez être préparé, mais qui peut être compensé par une conception peu avancée, mais elle peut être réduite avec un peu de prévoyance et d’expérience..

7. Interaction tactile et logique du jeu

Il est maintenant temps de mettre en œuvre la logique du jeu et de nous permettre d'interagir avec lui par le toucher. Commencez par décommenter le première carte déclaration de propriété dans le Une manette classe:

var firstCard: Carte?

Rappelons que la logique du jeu consiste à révéler deux cartes, l'une après l'autre. Cette variable permet de savoir si un joueur qui joue une carte est la première des deux ou non.

Ajoutez la méthode suivante au bas de la Une manette classe, avant l'accolade finale:

func handleTap (gr: UITapGestureRecognizer) let v = view.hitTest (gr.locationInView (view), withEvent: nil)! si laissez carte = v comme? Card UIView.transitionWithView (card, durée: 0,5, options: .TransitionFlipFromLeft, animations: card.image = UIImage (nommé: String (card.tag))) // gestionnaire d'achèvement final: _ dans card.userInteractionEnabled = false si laissez pCard = self.firstCard si pCard.tag == card.tag UIView.animateWithDuration (0.5, animations: card.alpha = 0.0, complétion: _ dans card.removeFromSuperview ()) UIView.animateWithDuration (0.5, animations: pCard.alpha = 0.0, complétion: _ dans pCard.removeFromSuperview ()) else UIView.transitionWithView (card, durée: 0.5, options: .TransitionFlipFromLeft, animations: card.image = self.backImage) _ dans card.userInteractionEnabled = true UIView.transitionWithView (pCard, durée: 0,5, options: .TransitionFlipFromLeft, animations: pCard.image = self.backImage) _ dans pCard.userInteractionEnabled = true  self.firstCard = nil else self.firstCard = carte

C'est une méthode longue. En effet, il regroupe en une méthode toute la manipulation tactile requise, la logique de jeu et les animations associées. Voyons comment cette méthode fait son travail:

  • Tout d'abord, il y a une vérification pour s'assurer que l'utilisateur a réellement touché un Carte exemple. C'est pareil comme? construire que nous avons utilisé plus tôt.
  • Si l'utilisateur a touché un Carte Par exemple, nous le retournons en utilisant une animation similaire à celle que nous avons implémentée plus tôt. Le seul aspect nouveau est que nous utilisons le gestionnaire d'achèvement, qui s'exécute une fois l'animation terminée, pour désactiver temporairement les interactions tactiles de cette carte en définissant le paramètre userInteractionEnabled propriété de la carte. Cela empêche le joueur de retourner la même carte. Noter la _ dans construction qui est utilisée plusieurs fois dans cette méthode. C’est juste pour dire que nous voulons ignorer la Bool paramètre que prend le gestionnaire d'achèvement.
  • Nous exécutons le code selon que le première carte une valeur non nulle a été attribuée à l'aide de la liaison facultative, bien connue de Swift. si laisse construction.
  • Si première carte est non nul, alors c’était la deuxième carte de la séquence que le joueur a retournée. Nous devons maintenant comparer le visage de cette carte avec le précédent (en comparant les étiquette valeurs) pour voir si nous avons obtenu une correspondance ou non. Si nous le faisions, nous animerions le fondu des cartes (en définissant leur alpha à 0). Nous retirons également ces cartes de la vue. Si les étiquettes ne sont pas égales, ce qui signifie que les cartes ne correspondent pas, il suffit de les retourner face vers le bas et de les définir. userInteractionEnabled à vrai afin que l'utilisateur puisse les sélectionner à nouveau.
  • Basé sur la valeur actuelle de première carte, nous avons mis à néant ou à la carte présente. Voici comment nous commutons le comportement du code entre deux touches successives.

Enfin, décommentez les deux déclarations suivantes du Une manetteL'initialiseur qui ajoute un identificateur de gestes tactiles à la vue. Lorsque le dispositif de reconnaissance des gestes du tap détecte un tap, le handleTap () La méthode est invoquée:

let tap = UITapGestureRecognizer (cible: self, action: #selector (GameController.handleTap (_ :))) view.addGestureRecognizer (tap)

Retournez à la chronologie du terrain de jeu et jouez au jeu de mémoire. N'hésitez pas à diminuer le grand rembourrage nous avons assigné un peu plus tôt.

Le code en handleTap (_ :) est à peu près la version non ornée de ce que j’écrivis la première fois. On pourrait objecter qu’en tant que méthode unique, on en fait trop. Ou que le code n'est pas assez orienté objet et que la logique et les animations de retournement de carte doivent être soigneusement intégrées aux méthodes du Carte classe. Tant que ces objections ne sont pas invalides en soi, Rappelez-vous que ce didacticiel est axé sur le prototypage rapide et que, dans la mesure où nous n'avions prévu aucune interaction avec cette partie du code sur le terrain de jeu, nous pouvions nous permettre d'être un peu plus "hack-ish"..

Une fois que quelque chose fonctionne et que nous décidons de poursuivre l'idée plus loin, nous devrons certainement envisager de refactoriser le code. En d’autres termes, commencez par le faire fonctionner, puis rendez-le rapide / élégant / joli /…

8. Toucher la manipulation sur le terrain de jeu

Bien que la partie principale du didacticiel soit maintenant terminée, je tiens à vous montrer comment nous pouvons écrire du code de manipulation tactile directement dans la cour de récréation. Nous allons d’abord ajouter une méthode à la Une manette classe qui nous permet de jeter un coup d'oeil sur les faces des cartes. Ajoutez le code suivant au Une manette classe, immédiatement après la handleTap (_ :) méthode:

public func quickPeek () pour v dans view.subviews si let card = v as? Card card.userInteractionEnabled = false UIView.transitionWithView (card, durée: 1.0, options: .TransitionFlipFromLeft, animations: card.image = UIImage (nommé: String (card.tag))) _ dans UIView.transitionWithView (card , durée: 1.0, options: .TransitionFlipFromLeft, animations: card.image = self.backImage) _ dans card.userInteractionEnabled = true

Supposons que nous voulions avoir la possibilité d'activer ou de désactiver cette fonction "Quick Peek" depuis la cour. Une façon de le faire serait de créer un public Bool propriété dans le Une manette classe que nous pourrions mettre dans la cour. Et bien sûr, nous devrions écrire un gestionnaire de gestes dans le Une manette classe, activée par un geste différent, qui invoquerait coup d'oeil rapide().

Une autre solution consisterait à écrire le code de traitement des gestes directement dans la cour de récréation. L’avantage de procéder de la sorte est que nous pourrions incorporer du code personnalisé en plus des appels. coup d'oeil rapide(). C'est ce que nous ferons ensuite. Ajoutez le code suivant au bas de la cour de récréation:

classe LPGR static var counter = 0 @objc static func longPressed (lp: UILongPressGestureRecognizer) if lp.state == .Began gc.quickPeek () counter + = 1 print ("Vous avez jeté un œil \ (compteur) time (s) . ") let longPress = UILongPressGestureRecognizer (cible: LPGR.self, action: #selector (LPGR.longPressed)) longPress.minimumPressDuration = 2.0 gc.view.addGestureRecognizer (longPress)

Pour activer la fonction de coup d’œil rapide, nous allons utiliser un geste long, c’est-à-dire que le joueur garde son doigt sur l’écran pendant un certain temps. Nous utilisons deux secondes comme seuil.

Pour gérer le geste, nous créons une classe, LPGR (bouton de reconnaissance de geste long abrégé), avec une statique propriété variable, compteur, pour savo