Rapid, prototip interactiv cu terenuri de joacă Xcode

Ce veți crea

Introducere

De la introducerea lor în Xcode 6 alături de Swift, la actuala lor versiune în Xcode 7.3.1, locurile de joacă au parcurs un drum lung. Cu noi caracteristici și o mai bună stabilitate, acestea se transformă într-un instrument viabil pentru prototipuri rapide sau rapid hacking împreună o dovadă a conceptului.

În calitate de dezvoltator, uneori aveți o sursă de inspirație sub forma unei idei interesante pentru o aplicație și doriți să codificați rapid un prototip care reprezintă esența goală a ideii dvs. Sau doriți doar să vă verificați înțelegerea modului în care se va comporta o anumită parte a codului UIKit. Dacă sunteți ca mine, preferați să evitați dificultatea de a crea un proiect Xcode și de a avea de-a face cu o multitudine de factori, cum ar fi tipurile de dispozitive și rezoluții, și a crea setări. Aceste decizii pot fi amânate până după ce v-ați gândit că ideea de bază merită să fie urmărită.

În acest tutorial, vom crea un joc de memorie bazat pe carte, toate în limitele unui loc de joacă. Este un joc comun, bine-cunoscut, deci nu există nici un credit pentru originalitate. Jocul este format din opt perechi de cărți identice (deci un total de 16 cărți) plasate cu fața în jos într-o grilă de 4x4.

Jucătorul trebuie să răstoarne două cărți ale căror fețe sunt dezvăluite pe scurt și apoi repetate înapoi. Obiectivul jocului este ca jucătorul să încerce să-și amintească pozițiile cărților și să descopere perechi identice, care apoi sunt scoase din joc. Jocul se termină când grilă este șters.

Jocul este bazat pe atingere și include animații simple de vizualizare. Afli cum poți să faci modificări în aplicația ta și să vezi în direct rezultatul schimbărilor tale.

1. Noțiuni de bază

Activați Xcode și selectați Nou> Loc de joaca ... din Xcode Fişier meniul. Dați locului de joacă un nume, cum ar fi MemoryGameXCPTut, a stabilit Platformă la iOS, și salvați locul de joacă. Folosesc Xcode 7.3.1 pentru acest tutorial.

Găsirea drumului tău în jurul locului de joacă

Să ne petrecem puțin timp familiarizându-ne cu interfața de joacă. Simțiți-vă liber să eliminați această secțiune dacă sunteți deja familiarizat cu locurile de joacă.

Un loc de joacă poate avea mai multe pagini, fiecare asociat cu propria vizualizare live și propriile foldere sursă / resurse. Nu vom folosi mai multe pagini în acest tutorial. Locurile de joacă acceptă formatarea marcajului care vă permite să adăugați text bogat la un loc de joacă și o legătură între paginile de teren de joacă.

Primul lucru pe care îl vedeți după crearea unui loc de joacă este editorul sursă de loc de joacă. Aici scrieți codul, care are un efect imediat asupra vederii live. Una dintre modalitățile de a comuta aspectul (dis) al Project Navigator utilizează comanda rapidă Comandă-0. În Project Navigator, puteți vedea două dosare, surse și Resurse.

surse

În surse , puteți adăuga codul auxiliar în unul sau mai multe fișiere Swift, cum ar fi clasele personalizate, controlorii de vizualizare și vizualizările. Chiar dacă majoritatea codului care definește logica prototipului dvs. este acolo, este auxiliară în sensul că este ascuns în fundal atunci când vă vedeți aplicația live.

Avantajul introducerii codului auxiliar în surse este că este compilat automat de fiecare dată când modificați și salvați fișierul. În acest fel, obțineți feedback mai rapid în vizualizarea live din modificările aduse locului de joacă. Înapoi în locul de joacă, puteți accesa public proprietățile și metodele pe care le expuneți în codul auxiliar care influențează modul în care se comportă aplicația dvs..

Resurse

Puteți adăuga resurse externe, cum ar fi imagini, în Resurse pliant.

În acest tutorial, trebuie să treceți frecvent între un fișier Swift pe care îl creăm în surse folderul și fișierul de teren de joacă (tehnic, de asemenea, un fișier Swift, cu excepția cazului în care nu vă veți referi la numele său de fișier). De asemenea, facem uz de Editor asistent în tutorial, având afișarea acestuia Cronologie, pentru a vedea ieșirea live în paralel cu codul locului de joacă. Orice schimbări pe care le faceți în loc de joacă se reflectă instantaneu (bine, în câteva secunde) la ieșirea live. De asemenea, puteți interacționa cu vizualizarea live și elementele interfeței cu utilizatorul. Pentru a vă asigura că puteți face toate acestea, luați o privire rapidă la figura de mai jos.

Potrivit numerelor verzi pe care le-am adăugat la figură:

  1. Acest buton ascunde Editor asistent astfel că numai editorul principal este vizibil.
  2. Acest buton dezvăluie Editor asistent. Editor asistent este vizibil în partea dreaptă a editorului principal. Acest editor vă poate ajuta prin afișarea de fișiere relevante, cum ar fi omologul fișierului din editorul principal.
  3. De la stânga la dreapta, aceste două butoane sunt utilizate, respectiv, pentru a comuta aspectul Project Navigator și consolă de depanare. În consola, putem verifica, printre altele, rezultatele ieșirilor de tipărire.
  4. sari bar în partea de sus a editorului principal poate fi, de asemenea, utilizat pentru a naviga la un anumit fișier. Apăsând de două ori pe numele proiectului, veți reveni la locul de joacă. Alternativ, puteți utiliza și Project Navigator.

Uneori, când vizionați terenul de joacă, trebuie să vă asigurați că Editor asistent afișează Cronologie în loc de alt dosar. Figura de mai jos arată cum se face acest lucru. În Editor asistent, Selectați Cronologie, omologul locului de joacă, în loc de Manual, care vă permite să afișați orice fișier în Editor asistent.

Când editați un fișier sursă din surse dosar, ca și contrapartea acestuia, Editor asistent arată interfața codului dvs., adică declarații și prototipuri de funcții fără implementările acestora. Prefer să ascund Editor asistent când lucrez la un dosar în surse și expuneți numai Editor asistent în loc de joacă pentru a vedea vizualizarea live.

Pentru a accesa abilitățile speciale ale locurilor de joacă, trebuie să importați modulul XCPlayground.

import XCPlayground

Ați setat LiveView proprietate a pagina curenta din XCPlaygroundPage obiecte față de un obiect care este conform cu  XCPlaygroundLiveViewable protocol. Aceasta poate fi o clasă personalizată sau poate fi o clasă UIView sau UIViewController instanță.

Adăugarea fișierelor în dosarul Surse / resurse

Am adăugat câteva imagini cu care putem lucra în acest tutorial. Descărcați imaginile, extrageți arhiva și adăugați imaginile în Imagini dosar la Resurse folder al locului de joacă din Project Navigator.

Asigurați-vă că trageți doar imaginile, astfel încât fiecare fișier imagine să se afle în Resurse dosar, nu în Resurse / Imagini.

Ștergeți codul în loc de joacă. Faceți clic dreapta pe surse și selectați Fișier nou din meniu. Setați numele fișierului la Game.swift.

2. Scrierea de clase și metode de ajutor

Adăugați următorul cod la Game.swift. Asigurați-vă că salvați fișierul după fiecare adăugare de cod.

import UIKit import XCPlayground import GameplayKit // (1) extensie publică UIImage // (2) public init comoditate (culoare: UICcolor, dimensiune: CGSize = CGSize (lățime: 1, înălțime: OrigineFile (rect) a permite imaginea = UIGraphicsGetImageFromCurrentImageContext () UIGraphicsEndImageContext () paza cgImage = image.CGImage else return nil . Inițială (CGImage: cgImage) permite cardWidth = CGFloat (120) // (3) permite cardHeight = CGFloat (141) init (imagine: UIImage ?, x: int, y: int) self.x = x self.y = y super.init (imagine: imagine) self.backgroundColor = .grayColor () self.layer.cornerRadius = .userInteractionEnabled = true public init necesar (coder aDecoder: NSCoder) fatalError ("init (coder :) nu a fost implementat")

Am adăugat câteva comentarii numerotate pentru a explica unele secțiuni ale implementării:

  1. Pe lângă UIKit și XCPlayground, importăm și noi GamePlayKit. Acest cadru include o metodă convenabilă care ne va ajuta să implementăm o metodă de amestecare aleatorie a unei matrice.
  2. Această extensie este activată UIImage ne permite, cu ajutorul UIKit metode, pentru a face imagini cu o culoare solidă de orice dimensiune dorim. Vom folosi acest lucru pentru a seta imaginea de fundal inițială a cărților de joc.
  3.  cardHeight și cardWidth constantele reprezintă dimensiunile imaginilor de pe baza cărora vom calcula alte dimensiuni.
  4. Card clasă, moștenind de la UIImageView, reprezintă o carte. Deși am stabilit câteva proprietăți în Card clasa, scopul principal al creării acestei clase este de a ne ajuta să identificăm și să repetăm ​​subdiviziuni care corespund cărților de joc din joc. Cardurile au și proprietăți X și y să-și amintească poziția lor în rețea.

3. Vizualizați controlerul

Adăugați următorul cod la Game.swift, imediat după codul anterior:

clasa publica GameController: UIViewController // (1): variabile publice astfel incat sa putem manipula in loc de joaca public var padding = CGFloat (20) / * didSet resetGrid () / public var backImage: UIImage = UIImage culoare: .redColor (), dimensiune: CGSize (latime: cardWidth, height: cardHeight))! // (2): proprietăți calculate var viewWidth: CGFloat get retur 4 * cardWidth + 5 * padding var viewHeight: CGFloat get return 4 * cardHeight + 5 padding var shuffledNumbers = // stochează numerele cardului amestecate // var firstCard: Card? // uncomment mai târziu public init () super.init (nibName: nul, bundle: nil) preferatContentSize = CGSize (latime: viewWidth, height: viewHeight) shuffle (țintă: auto, acțiune: #selector (GameController.handleTap (_ :))) // view.addGestureRecognizer (tap) public init necesar (coder aDecoder: NSCoder) fatalError implementat ") suprascriere publică func loadView () view = UIView () view.backgroundColor = .blueColor () view.frame = CGRect (x: 0, y: 0, width: viewWidth, height: viewHeight) 3): Folosind API-ul GameplayKit pentru a genera un amestec al matricei [1, 1, 2, 2, ..., 8, 8] func shuffle () let numere = (1 ... 8) .flatMap [$ 0, $ 0] shuffledNumbers = GKRandomSource.sharedRandom (). arrayByShufflingObjectsInArray (numere) ca! [Int] // (4): Convertiți de la poziția cardului pe grilă pentru a indexa în numerele de card amestecate array func cardNumberAt (x: Int, _ y: Int) -> Int assert <= 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. Cele două proprietăți, umplutură și backImage, sunt declarate public astfel încât să le putem accesa mai târziu în loc de joacă. Acestea reprezintă spațiul gol din jurul cardurilor din rețea și imaginea afișată pe partea din spate a fiecărui card. Rețineți că ambele proprietăți au primit valori inițiale, reprezentând o umplutură de 20 și o culoare roșie solidă pentru imaginea laterală a cardului. Acum puteți ignora codul comentat.
  2. Calculăm lățimea și înălțimea dorită a vederilor prin intermediul proprietăților calculate. Pentru a înțelege viewWidth calculați, amintiți-vă că există patru cărți în fiecare rând și trebuie să luăm în considerare și umplutura fiecărui card. Aceeași idee se aplică și viewHeight calcul.
  3. Codul (1 ... 8) .flatMap [$ 0, $ 0] este un mod concis de a produce matricea [1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8]. Dacă nu sunteți familiarizat cu programarea funcțională, puteți scrie și a pentru-pentru a genera matricea. Utilizarea metodelor din GamePlayKit cadru, vom amesteca numerele în matrice. Numerele corespund celor opt perechi de cărți. Fiecare număr reprezintă imaginea cardului cu același nume (de exemplu, o valoare de 1 în shuffledArray corespunde 1.png).
  4. Am scris o metodă care găsește locația unei cartele pe grilă 4x4 la locația acesteia în shuffledNumbers matrice de lungime 16. Factorul 4 în calculul aritmetic reflectă faptul că avem patru cărți pe rând.
  5. Avem, de asemenea, o metodă care indică poziția unei cărți centru proprietate) în grilă, pe baza dimensiunilor cardului și a umpluturii.
  6. setupGrid () metoda se numește în timpul inițializării controlerului de vizualizare. Ea stabilește 4x4 Card grilă. De asemenea, atribuie identitatea fiecărei cărți pe baza shuffledNumbers array și îl stochează în etichetă proprietate moștenită de la clasa de bază a cardului, UIView. În logica jocului, comparăm etichetă valori pentru a afla dacă două cărți se potrivesc sau nu. Această schemă de modelare destul de rudimentară servește destul de bine pentru nevoile noastre actuale.
  7. Această piesă de cod neutilizată momentan ne va ajuta să repoziționăm cardurile în cazul în care se schimbă umplutura. Amintiți-vă că am declarat umplutură proprietatea ca proprietate publică, astfel încât să putem accesa terenul de joacă.
  8. Codul din viewDidAppear (_ :) rulează imediat după ce vizualizarea controlerului de vizualizare devine vizibilă. Noi iterați prin subview-urile de vizualizare și, dacă subview-ul este o instanță a lui Card clasă, (verificată prin la fel de? operatorul de downcasting fals) corpul dacă-declarația definește tranziția de efectuat. Aici vom schimba imaginea afișată pe carduri, din imaginea desenată a desenelor animate, care definește fața fiecărui card la imaginea (comună) backImage din toate cardurile. Această tranziție este însoțită de o animație flip stânga-dreapta care dă aspectul cărților care au fost transformate fizic. Dacă nu sunteți familiarizat cu modul în care UIView animații de lucru, acest lucru ar putea părea un pic ciudat. Chiar dacă am adăugat secvențial animația fiecărei cărți într-o buclă, animațiile sunt introduse într-o singură tranzacție de animație și executate simultan, adică, cărțile se învârtesc împreună.

Reveniți la locul de joacă și înlocuiți orice text din editor cu următoarele:

importați importul XCPlayground UIKit let gc = GameController () XCPlaygroundPage.currentPage.liveView = gc

Asigurați-vă că cronologia este vizibilă. Vederea controlorului de vedere ar trebui să apară la viață și să ne arate o grilă de 4x4 de cărți cu animale desene animate care se răstoarnă pentru a ne arăta partea din spate a cărților. Chiar acum, nu putem face prea mult cu această viziune, pentru că nu am programat nici o interacțiune în ea încă. Dar este cu siguranta un inceput.

4. Modificarea variabilelor în spațiul de joacă

Acum, să schimbăm fețele posterioare ale cardurilor de la roșu roșu la o imagine, mai precis b.png în Resurse pliant. Adăugați următoarea linie în partea de jos a locului de joacă.

gc.backImage = UIImage (numit: "b")!

După o secundă sau două, veți vedea că fețele din spate ale cardurilor s-au schimbat de la roșu simplu la o mână de desene animate.

Să încercăm acum să schimbăm umplutură proprietate, pe care le-am atribuit o valoare implicită de 20 in Game.swift. În consecință, spațiul dintre carduri ar trebui să crească. Adăugați următoarea linie în partea de jos a locului de joacă:

gc.padding = 75

Așteptați ca vizualizarea live să se refacă și să vedeți că ... nimic nu sa schimbat.

5. O scurtă ocolire

Pentru a înțelege ce se întâmplă, trebuie să rețineți că entitățile, cum ar fi controlorii de vizualizare și opiniile asociate, au un ciclu de viață complex. Vom concentra asupra celor din urmă, adică asupra punctelor de vedere. Crearea și actualizarea vizualizării unui controler de vizualizare este un proces în mai multe etape. În anumite puncte ale ciclului de viață al vizualizării, se emită notificări către UIViewController, informându-l despre ce se întâmplă. Mai important, programatorul se poate conecta la aceste notificări introducând codul pentru a direcționa și personaliza acest proces.

 loadView () și viewDidAppear (_ :) Metodele sunt două metode pe care le-am folosit pentru a ne apropia de ciclul de viață al vederii. Acest subiect este oarecum implicat și dincolo de sfera acestei discuții, însă ceea ce contează pentru noi este faptul că codul de pe terenul de joacă, după atribuirea controlorului de vizualizare ca loc de joacă LiveView, este executat ceva timp între apelul către viewWillAppear (_ :) și apelul către viewDidAppear (_ :). Puteți verifica acest lucru modificând unele proprietăți în loc de joacă și adăugați instrucțiuni de imprimare la aceste două metode pentru a afișa valoarea acestei proprietăți.

Problema cu valoarea umplutură care nu are efectul vizual așteptat este că, până în acel moment, viziunea și subiecțiile ei au fost deja stabilite. Rețineți că, ori de câte ori faceți o modificare a codului, terenul de joacă este reluat de la început. În acest sens, această problemă nu este specifică locurilor de joacă. Chiar dacă ați dezvoltat codul pentru a rula pe simulator sau pe un dispozitiv fizic, de multe ori ar trebui să scrieți un cod suplimentar pentru a vă asigura că modificarea valorii unei proprietăți are efectul dorit asupra aspectului sau conținutului vizualizării.

S-ar putea să întrebați de ce am putut schimba valoarea backImage proprietate și a vedea rezultatul fără a face nimic special. Observați că backImage proprietate este de fapt folosit pentru prima dată în viewDidAppear (_ :), moment în care și-a dobândit deja noua valoare.

6. Observarea proprietăților și luarea de măsuri

Modul nostru de a face față acestei situații va fi monitorizarea modificărilor valorii umplutură și redimensionarea / repoziționarea vizualizărilor și sub-vizualizărilor. Din fericire, acest lucru este ușor de a face cu Swift la îndemână respectarea proprietății caracteristică. Începeți prin dezarhivarea codului pentru resetGrid () metoda în Game.swift:

// (7): resetare grid func resetGrid () view.frame = CGRect (x: 0, y: 0, lățime: viewWidth, height: viewHeight) pentru v în view.subviews if let card = v as? Cartela card.center = centerOfCardAt (card.x, card.y)

Această metodă recompensează poziția cadrului vizual și a fiecăruia dintre ele Card Obiect bazat pe noile valori ale viewWidth și viewHeight. Amintiți-vă că aceste proprietăți sunt calculate pe baza valorii umplutură, care tocmai a fost modificată.

De asemenea, modificați codul pentru umplutură pentru a utiliza didSet observator al cărui corp, după cum indică numele, execută ori de câte ori setăm valoarea lui umplutură:

// (1): variabilele publice astfel încât să le putem manipula în locurile de joacă publice var padding = CGFloat (20) didSet resetGrid ()

resetGrid () metoda se deschide și vizualizarea este actualizată pentru a reflecta spațiile noi. Puteți verifica acest lucru în loc de joacă.

Se pare că am reușit să rezolvăm lucrurile destul de ușor. În realitate, când am decis prima dată, am vrut să pot interacționa cu umplutură proprietate, a trebuit să mă întorc și să fac modificări în codul din Game.swift. De exemplu, a trebuit să fac abstracție Card centrului într-o funcție separată (centerOfCardAt (_: _ :)) să calculeze curat și independent pozițiile cărților ori de câte ori ar fi trebuit să fie stabilite.

Efectuarea de proprietăți calculate pentru viewWidth și viewHeight de asemenea, a ajutat. În timp ce acest tip de rescriere este ceva ce ar trebui să fii pregătit pentru ca un compromis de a nu face mult proiectarea în avans, poate fi redusă cu puțină preocupare și experiență.

7. Interacțiunea logică și atingere a jocului

Acum este momentul să implementăm logica jocului și să ne permitem să interacționăm cu el prin atingere. Începeți prin a dezinstala firstCard declarația de proprietate în Controlor de joc clasă:

var firstCard: Card?

Amintiți-vă că logica jocului implică dezvăluirea a două cărți, una după alta. Această variabilă ține evidența dacă un flip efectuat de către jucător este primul dintre cei doi sau nu.

Adăugați următoarea metodă în partea de jos a paginii Controlor de joc clasa, înainte de a încheia brățară curly:

func handleTap (gr: UITapGestureRecognizer) permite v = view.hitTest (gr.locationInView (vedere), cuEvent: nil)! dacă lăsați card = v ca? Card UIView.transitionWithView (carte, durată: 0.5, opțiuni: .TransitionFlipFromLeft, animații: card.image = UIImage (numit: String (card.tag)) // card.userInteractionEnabled = false dacă permiteți pCard = self.firstCard if pCard.tag == card.tag UIView.animateWithDuration (0.5, animații: card.alpha = 0.0, completare: _ în card.removeFromSuperview ()) UIView.animateWithDuration (0.5, animații: pCard.alpha = 0.0, completare: _ în pCard.removeFromSuperview ()) altceva UIView.transitionWithView (carte, durată: 0.5, opțiuni: .TransitionFlipFromLeft, animații: card.image = (pCard, durata: 0.5, opțiuni: .TransitionFlipFromLeft, animații: pCard.image = auto.backImage) _ în pCard.userInteractionEnabled = true  self.firstCard = nil altceva self.firstCard = card

Aceasta este o metodă de lungă durată. Acest lucru se datorează faptului că îmbină toate manipularea tactilă necesară, logica jocului, precum și animațiile asociate într-o singură metodă. Să vedem cum funcționează această metodă:

  • În primul rând, există o verificare pentru a se asigura că utilizatorul a atins de fapt a Card instanță. Asta e lafel la fel de? construi pe care am folosit-o mai devreme.
  • Dacă utilizatorul a atins a Card de exemplu, îl răsturnăm folosind o animație similară celei pe care am implementat-o ​​mai devreme. Singurul aspect nou este că folosim instrumentul de completare care se execută după finalizarea animației pentru a dezactiva temporar interacțiunile de atingere pentru acel card prin setarea userInteractionEnabled proprietatea cardului. Acest lucru împiedică playerul să răstoarne pe același card. Rețineți _ în construct care este folosit de mai multe ori în această metodă. Aceasta este doar pentru a spune că vrem să ignorăm bool parametrul pe care îl are managerul de finalizare.
  • Noi executam codul bazat pe daca firstCard a fost atribuită o valoare non-zero utilizând legarea opțională, cunoscută de Swift dacă lăsați construi.
  • Dacă firstCard este non-zero, atunci acesta a fost cel de-al doilea carton al secvenței pe care jucătorul a dat-o. Acum trebuie să comparăm fața acestei cărți cu cea precedentă (prin compararea cu etichetă valori) pentru a vedea dacă am obținut un meci sau nu. Dacă am făcut-o, animăm cardurile care se estompează (prin setarea lor alfa la 0). De asemenea, eliminăm aceste cărți din vizualizare. Dacă etichetele nu sunt egale, adică nu se potrivesc cardurile, le înșelăm pur și simplu cu fața în jos și setăm userInteractionEnabled la Adevărat astfel încât utilizatorul să le poată selecta din nou.
  • Pe baza valorii curente a firstCard, am pus-o la fiecare zero sau la cardul prezent. Acesta este modul în care schimbăm comportamentul codului între două atingeri succesive.

În cele din urmă, dezactivați următoarele două afirmații în Controlor de joccare inițiază adăugarea unui recunoaștere a gestului de atingere în vizualizare. Atunci când instrumentul de recunoaștere a gestului de atingere detectează un robinet, handleTap () se invocă metoda:

lasati apasat = UITapGestureRecognizer (target: self, action: #selector (GameController.handleTap (_ :)) view.addGestureRecognizer (apasati)

Întoarceți-vă la cronometrul locului de joacă și jucați jocul de memorie. Simțiți-vă liber să micșorați imaginile mari umplutură ne-am atribuit un pic mai devreme.

Codul din handleTap (_ :) este destul de mult versiunea neimplicată a ceea ce am scris prima dată. S-ar putea ridica obiecția că, ca o singură metodă, face prea mult. Sau că codul nu este suficient de orientat spre obiect și că logica și animațiile care aruncă cartela ar trebui să fie îndepărtate îndeaproape în metodele Card clasă. În timp ce aceste obiecții nu sunt nevalide în sine, amintiți-vă că prototipul rapid este centrul acestui tutorial și deoarece nu am prevăzut nici o nevoie de a interacționa cu această parte a codului în loc de joacă, ne-am putea permite să fim un pic mai "hack-ish".

Odată ce avem ceva de lucru și hotărâm că vrem să continuăm această idee, ar trebui cu siguranță să luăm în considerare codificarea refactorizării. Cu alte cuvinte, mai intai faceti-o sa functioneze, apoi faceti-l rapid / elegant / frumos / ...

8. Atingeți Manipularea în loc de joacă

În timp ce partea principală a tutorialului este acum terminată, ca pe o parte interesantă, vreau să vă arăt cum putem scrie codul de manipulare a atingerii direct pe terenul de joacă. Mai întâi vom adăuga o metodă la Controlor de joc clasa care ne permite să aruncăm o privire asupra fețelor cărților. Adăugați următorul cod la Controlor de joc clasa, imediat după handleTap (_ :) metodă:

public func quickPeek () pentru v în view.subviews if let card = v as? Card card.userInteractionEnabled = fals UIView.transitionWithView (card, durată: 1.0, opțiuni: .TransitionFlipFromLeft, animații: card.image = UIImage (numit: String (card.tag))) _in UIView.transitionWithView , durata: 1.0, opțiuni: .TransitionFlipFromLeft, animații: card.image = self.backImage) _ în card.userInteractionEnabled = true

Să presupunem că dorim să activați sau să dezactivați această caracteristică "peek" rapidă din interiorul locului de joacă. O modalitate de a face acest lucru ar fi crearea unui public bool proprietate în Controlor de joc clasa pe care am putea să o punem la locul de joacă. Și, bineînțeles, trebuia să scriem un manipulator de gest în Controlor de joc clasa, activată de un alt gest, care ar fi invocat privire rapidă().

O altă modalitate ar fi să scrieți codul de manipulare a gesturilor direct în loc de joacă. Un avantaj de a face acest lucru este că am putea încorpora un cod personalizat în plus față de apel privire rapidă(). Așa vom face în continuare. Adăugați următorul cod în partea de jos a locului de joacă:

LPGR static var counter = 0 @objc static func longPressed (lp: UILongPressGestureRecognizer) dacă lp.state == .Began gc.quickPeek () counter + = 1 print (" . ") lăsați longPress = UILongPressGestureRecognizer (țintă: LPGR.self, acțiune: #selector (LPGR.longPressed)) longPress.minimumPressDuration = 2.0 gc.view.addGestureRecognizer (longPress)

Pentru a activa funcția Quick Peek, vom folosi un gest lung de presă, adică jucătorul își ține degetul pe ecran pentru o anumită perioadă de timp. Utilizăm două secunde ca prag.

Pentru a manipula gestul, vom crea o clasă, LPGR (abreviat recunoașterea gestului de presă lungă), cu a static proprietate variabilă, tejghea, pentru a urmări de câte ori am cercetat, și a static metodă longPressed (_ :) să se ocupe de gest.

Prin utilizarea funcției static calificativ, putem evita să creeze un LPGR deoarece entitățile declarate statice sunt asociate cu LPGR tip (clasa), mai degrabă decât cu o anumită instanță.

În afară de aceasta, nu există niciun avantaj special pentru această abordare. Din motive complicate, trebuie să marcăm metoda @objc pentru a păstra compilatorul fericit. Notați utilizarea LPGR.self să se refere la tipul obiectului. De asemenea, rețineți că în instrumentul de gest, verificăm dacă stat a gestului este .Au inceput. Acest lucru se datorează faptului că gestul de presare lung este continuu, adică funcționarul va executa repetat atâta timp cât utilizatorul își păstra degetul pe ecran. Deoarece dorim doar ca codul să fie executat o singură apăsare pe deget, o facem când gestul este recunoscut pentru prima dată.

Contorul de incrementare este codul personalizat pe care l-am introdus, care nu se bazează pe funcționalitatea oferită de Controlor de joc clasă. Puteți vizualiza ieșirea din imprimare(_:) (după ce a văzut de câteva ori) în consola din partea de jos.

Concluzie

Sperăm că acest tutorial a demonstrat un exemplu interesant de prototipuri rapide, interactive în locurile de joacă Xcode. Pe lângă motivele pentru utilizarea terenurilor de joacă pe care le-am menționat mai devreme, ați putea gândi alte scenarii în care ar putea fi utile. De exemplu:

  • demonstrând funcționalitatea prototipului clienților și lăsându-i să aleagă opțiunile și să facă personalizări cu feedback live și fără a fi nevoiți să se ocupe de detaliile codului.
  • dezvoltând simulări, cum ar fi pentru fizi
    Cod