Den här artikeln beskriver processen att skapa ett enkelt minnesträningsspel som jag verkligen gillar. Förutom att vara bra i sig kommer du att lära dig lite mer om Swift-klasser och protokoll allt eftersom. Men innan vi börjar, låt oss förstå själva spelet.
Påminnelse:för alla läsare av "Habr" - en rabatt på 10 000 rubel när du anmäler dig till någon Skillbox-kurs med hjälp av "Habr"-kampanjkoden.
Spelet börjar med en demonstration av en uppsättning kort. De ligger med framsidan nedåt (respektive bild nedåt). När du klickar på någon öppnas bilden i några sekunder.
Spelarens uppgift är att hitta alla kort med samma bilder. Om du, efter att ha öppnat det första kortet, vänder på det andra och bilderna matchar, förblir båda korten öppna. Om de inte stämmer överens stängs korten igen. Målet är att öppna allt.
Projektets struktur
För att skapa en enkel version av detta spel behöver du följande komponenter:
En styrenhet: GameController.swift.
One View: CardCell.swift.
Två modeller: MemoryGame.swift och Card.swift.
Main.storyboard för att säkerställa att hela uppsättningen av komponenter är tillgänglig.
Vi börjar med den enklaste komponenten i spelet, korten.
Card.swift
Kortmodellen kommer att ha tre egenskaper: id för att identifiera var och en, en boolesk variabel som visas för att specificera kortets status (dold eller öppen) och artworkURL för bilderna på korten.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Du behöver också dessa metoder för att kontrollera användarinteraktion med kartor:
Metod för att visa en bild på ett kort. Här återställer vi alla egenskaper till standard. För id genererar vi ett slumpmässigt id genom att anropa NSUUIS().uuidString.
Den andra modellen är MemoryGame, här sätter vi ett 4*4 rutnät. Modellen kommer att ha egenskaper som kort (en array av kort på ett rutnät), en cardsShown-array med kort som redan är öppna och en boolesk variabel är Spelar för att spåra spelets status.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Vi behöver också utveckla metoder för att styra användarinteraktion med nätet.
Denna metod läser det sista elementet i **cardsShown**-matrisen och returnerar det icke-matchande 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 och GameController.swift
Main.storyboard ser ut ungefär så här:
Till en början måste du ställa in det nya spelet som viewDidLoad i kontrollern, inklusive bilderna för rutnätet. I spelet kommer allt detta att representeras av 4*4 collectionView. Om du ännu inte är bekant med collectionView, här är den du kan få den information du behöver.
Vi kommer att konfigurera GameController som applikationens rotkontroller. GameController kommer att ha en collectionView som vi kommer att referera till som en IBOutlet. En annan referens är till knappen IBAction onStartGame(), detta är en UIButton, du kan se den i storyboarden som heter PLAY.
Lite om implementeringen av kontroller:
Först initierar vi två huvudobjekt - rutnätet: spel = MemoryGame(), och en uppsättning kort: kort = [Card]().
Vi ställer in de initiala variablerna som viewDidLoad, detta är den första metoden som anropas medan spelet körs.
collectionView är inställt på dold eftersom alla kort är dolda tills användaren trycker på SPELA.
Så fort vi trycker på SPELA startar avsnittet onStartGame IBAction och vi ställer in egenskapen collectionView isHidden på false så att korten kan bli synliga.
Varje gång användaren väljer ett kort anropas didSelectItemAt-metoden. I metoden kallar vi didSelectCard för att implementera huvudspelets logik.
Att arbeta med protokoll är kärnan i Swift-programmering. Protokoll ger möjlighet att definiera regler för en klass, struktur eller uppräkning. Denna princip låter dig skriva modulär och utbyggbar kod. I själva verket är detta ett mönster som vi redan implementerar för collectionView i GameController. Låt oss nu göra vår egen version. Syntaxen kommer att se ut så här:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Vi vet att ett protokoll låter dig definiera regler eller instruktioner för att implementera en klass, så låt oss fundera på vad de ska vara. Du behöver fyra totalt.
Spelstart: memoryGameDidStart.
Du måste vända kortet med framsidan nedåt: memoryGameShowCards.
Du måste vända kortet med framsidan nedåt: memoryGameHideCards.
Spelslut: memoryGameDidEnd.
Alla fyra metoderna kan implementeras för huvudklassen, som är GameController.
memoryGameDidStart
När denna metod körs bör spelet starta (användaren trycker på SPELA). Här laddar vi helt enkelt om innehållet genom att anropa collectionView.reloadData(), vilket kommer att blanda korten.
Vi kallar denna metod från collectionSDViewSelectItemAt. Först visar det det valda kortet. Kontrollerar sedan om det finns ett omatchat kort i arrayen CardsShown (om antalet kort som visas är udda). Om det finns ett, jämförs det valda kortet med det. Om bilderna är desamma läggs båda korten till korten som visas och förblir med framsidan uppåt. Om olika, lämnar kortet Visade kort och båda vänds nedåt.
memoryGameHideCards
Om korten inte matchar, anropas denna metod och kortbilderna döljs.
visat = falskt.
memoryGameDidEnd
När den här metoden anropas betyder det att alla kort redan är avslöjade och finns i listan över kort som visas: cardsShown.count = cards.count, så spelet är över. Metoden anropas specifikt efter att vi har anropat endGame() för att ställa in isPlaying var till false, varefter spelets slutmeddelande visas. Även alertController används som en indikator för styrenheten. viewDidDisappear anropas och spelet återställs.
Så här 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()
}
}
Det är faktiskt allt. Du kan använda det här projektet för att skapa din egen version av spelet.