Denne artikkelen beskriver prosessen med å lage et enkelt minnetreningsspill som jeg virkelig liker. Foruten å være god i seg selv, vil du lære litt mer om Swift-klasser og protokoller etter hvert. Men før vi begynner, la oss forstå selve spillet.
Vi minner om:for alle lesere av "Habr" - en rabatt på 10 000 rubler når du melder deg på et hvilket som helst Skillbox-kurs ved å bruke kampanjekoden "Habr".
Spillet begynner med en demonstrasjon av et sett med kort. De ligger med forsiden ned (henholdsvis bildet ned). Når du klikker på en, åpnes bildet i noen sekunder.
Spillerens oppgave er å finne alle kortene med de samme bildene. Hvis du, etter å ha åpnet det første kortet, snur det andre og bildene stemmer overens, forblir begge kortene åpne. Hvis de ikke stemmer overens, lukkes kortene igjen. Målet er å åpne alt.
Prosjektstruktur
For å lage en enkel versjon av dette spillet trenger du følgende komponenter:
Én kontroller: GameController.swift.
One View: CardCell.swift.
To modeller: MemoryGame.swift og Card.swift.
Main.storyboard for å sikre at hele settet med komponenter er tilgjengelig.
Vi starter med den enkleste komponenten i spillet, kortene.
Card.swift
Kortmodellen vil ha tre egenskaper: id for å identifisere hver enkelt, en boolsk variabel vist for å spesifisere statusen til kortet (skjult eller åpen), og artworkURL for bildene på kortene.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Du trenger også disse metodene for å kontrollere brukerinteraksjon med kart:
Metode for å vise et bilde på et kort. Her tilbakestiller vi alle egenskaper til standard. For id genererer vi en tilfeldig id ved å kalle NSUUIS().uuidString.
Den andre modellen er MemoryGame, her setter vi et 4*4 rutenett. Modellen vil ha egenskaper som kort (en matrise med kort på et rutenett), en cardsShown-matrise med kort som allerede er åpne, og en boolsk variabel er Playing for å spore statusen til spillet.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Vi må også utvikle metoder for å kontrollere brukerinteraksjon med nettet.
Denne metoden leser det siste elementet i **cardsShown**-matrisen og returnerer det ikke-matchende kortet.
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 og GameController.swift
Main.storyboard ser omtrent slik ut:
Til å begynne med må du sette det nye spillet som viewDidLoad i kontrolleren, inkludert bildene for rutenettet. I spillet vil alt dette bli representert av en 4*4 samlingsvisning. Hvis du ennå ikke er kjent med collectionView, er den her du kan få den informasjonen du trenger.
Vi vil konfigurere GameController som applikasjonens rotkontroller. GameController vil ha en samlingsvisning som vi vil referere til som en IBOutlet. En annen referanse er til IBAction onStartGame()-knappen, dette er en UIButton, du kan se den i storyboardet som heter PLAY.
Litt om implementeringen av kontrollere:
Først initialiserer vi to hovedobjekter - rutenettet: spill = MemoryGame(), og et sett med kort: kort = [Card]().
Vi setter startvariablene som viewDidLoad, dette er den første metoden som kalles mens spillet kjører.
collectionView er satt til skjult fordi alle kortene er skjult til brukeren trykker PLAY.
Så snart vi trykker PLAY starter onStartGame IBAction-delen, og vi setter egenskapen collectionView isHidden til false slik at kortene kan bli synlige.
Hver gang brukeren velger et kort, kalles didSelectItemAt-metoden. I metoden kaller vi didSelectCard for å implementere hovedspilllogikken.
Her er den endelige GameController-implementeringen:
Arbeid med protokoller er kjernen i Swift-programmering. Protokoller gir muligheten til å definere regler for en klasse, struktur eller oppregning. Dette prinsippet lar deg skrive modulær og utvidbar kode. Faktisk er dette et mønster som vi allerede implementerer for collectionView i GameController. La oss nå lage vår egen versjon. Syntaksen vil se slik ut:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Vi vet at en protokoll lar oss definere regler eller instruksjoner for implementering av en klasse, så la oss tenke på hva de skal være. Du trenger fire totalt.
Spillstart: memoryGameDidStart.
Du må snu kortet med forsiden ned: memoryGameShowCards.
Du må snu kortet med forsiden ned: memoryGameHideCards.
Spillslutt: memoryGameDidEnd.
Alle fire metodene kan implementeres for hovedklassen, som er GameController.
memoryGameDidStart
Når denne metoden kjøres, skal spillet starte (brukeren trykker PLAY). Her laster vi ganske enkelt innholdet på nytt ved å ringe collectionView.reloadData(), som vil blande kortene.
Vi kaller denne metoden fra collectionSDViewSelectItemAt. Først viser den det valgte kortet. Sjekker deretter om det er et uovertruffent kort i kortene som vises (hvis antallet kort som vises er oddetall). Hvis det er en, sammenlignes det valgte kortet med det. Hvis bildene er like, legges begge kortene til kortene som vises og forblir med forsiden opp. Hvis det er forskjellig, etterlater kortet de viste kortene og begge vendes med forsiden ned.
memoryGameHideCards
Hvis kortene ikke stemmer, kalles denne metoden og kortbildene skjules.
vist = usant.
memoryGameDidEnd
Når denne metoden kalles, betyr det at alle kortene allerede er avslørt og er på listen over kort som vises: cardsShown.count = cards.count, så spillet er over. Metoden kalles spesifikt etter at vi har kalt endGame() for å sette isPlaying var til false, hvoretter meldingen om sluttspill vises. Også alertController brukes som en indikator for kontrolleren. viewDidDisappear kalles og spillet tilbakestilles.
Slik ser det ut i 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()
}
}
Egentlig er det alt. Du kan bruke dette prosjektet til å lage din egen versjon av spillet.