У гэтым артыкуле апісваецца працэс стварэння простай гульні для трэніроўкі памяці, якая мне вельмі падабаецца. Акрамя таго, што яна сама па сабе добрая, падчас працы вы крыху больш даведаецеся аб класах і пратаколах Swift. Але перш чым пачаць, давайце разбяромся ў самой гульні.
Нагадваем:для ўсіх чытачоў "Хабра" - зніжка 10 000 рублёў пры запісе на любы курс Skillbox па промакодзе "Хабр".
Гульня пачынаецца з дэманстрацыі набору картак. Яны ляжаць "кашуляй" уверх (адпаведна, выявай уніз). Калі вы клікаеце па любой, на некалькі секунд адчыняецца малюнак.
Задача гульца - знайсці ўсе карткі з аднолькавымі карцінкамі. Калі пасля адкрыцця першай карты вы пераварочваеце другую і карцінкі супадаюць, абедзве карткі застаюцца адкрытымі. Калі не супадаюць, карткі зноў зачыняюцца. Задача - адкрыць усё.
Структура праекту
Для таго, каб стварыць простую версію гэтай гульні патрэбны наступныя кампаненты:
Адзін кантролер (One Controller): GameController.swift.
Адзін прагляд (One View): CardCell.swift.
Дзве мадэлі (Two Models): MemoryGame.swift and Card.swift.
Main.storyboard для таго, каб увесь набор кампанентаў быў у наяўнасці.
Пачынаем з самага простага кампанента гульні, карткі.
Card.swift
У мадэлі карткі будзе тры ўласцівасці: id для ідэнтыфікацыі кожнай, лагічная зменная shown для ўдакладнення статуту карты (схаваная або адчыненая) і artworkURL для малюначкаў на картках.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Таксама будуць патрэбныя гэтыя метады для кіравання ўзаемадзеяннем карыстальніка з картамі:
Метад для вываду выявы на карту. Тут мы скідаем усе ўласцівасці на дэфолтныя. Для id генеруем выпадковы id шляхам выкліку NSUUIS().uuidString.
Метад для стварэння копіі кожнай карткі - Для таго, каб атрымаць большую колькасць аднолькавых. Гэты метад будзе вяртаць card з аналагічнымі значэннямі.
Другая мадэль – MemoryGame, тут задаем сетку 4*4. У мадэлі будуць такія ўласцівасці, як cards (масіў картак на сетцы), масіў cardsShown з ужо адчыненымі карткамі і лагічная зменная isPlaying для адсочвання статуту гульні.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Нам таксама трэба распрацаваць метады для кіравання ўзаемадзеяння карыстальніка з сеткай.
Гэты метад чытае апошні элемент у масіве cardsShown і вяртае неадпаведную картку.
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 і GameController.swift
Main.storyboard выглядае прыкладна так:
Першапачаткова ў кантролеры трэба ўсталяваць новую гульню як viewDidLoad, уключаючы выявы для сеткі. У гульні ўсё гэта будзе прадстаўлена 4*4 collectionView. Калі вы яшчэ не знаёмыя з collectionView, вось тут можна атрымаць патрэбную інфармацыю.
Мы наладзім GameController у якасці каранёвага кантролера прыкладання. У GameController будзе collectionView, на які мы будзем спасылацца ў якасьці IBOutlet. Яшчэ адна спасылка - на кнопку IBAction onStartGame (), гэта UIButton, яе вы можаце ўбачыць у раскадроўцы пад назвай PLAY.
Трохі аб рэалізацыі кантролераў:
Спачатку ініцыялізуем два галоўныя аб'екты — сетку (the grid): game = MemoryGame(), і на набор картак: cards = [Card]().
Усталеўваны пачатковыя зменныя як viewDidLoad, гэта першы метад, які выклікаецца падчас працы гульні.
collectionView усталёўваны як hidden, паколькі ўсе карты ўтоеныя да таго моманту, пакуль карыстач не націсне PLAY.
Як толькі націскаем PLAY, стартуе раздзел onStartGame IBAction, і мы выстаўляем уласцівасць collectionView isHidden як false, каб карткі маглі стаць бачнымі.
Кожны раз, калі карыстач выбірае картку, выклікаецца метад didSelectItemAt. У метадзе мы выклікаем didSelectCard для рэалізацыі асноўнай логікі гульні.
Цяпер давайце крыху спынімся на важных пратаколах.
пратаколы
Праца з пратаколамі - аснова асноў праграмавання на Swift. Пратаколы даюць магчымасць задаць правілы для класа, структуры ці пералічэнні. Гэты прынцып дазваляе пісаць модульны і які пашыраецца код. Фактычна гэта шаблон, які мы ўжо рэалізуем для collectionView у GameController. Цяпер зробім уласны варыянт. Сінтаксіс будзе выглядаць так:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Мы ведаем, што пратакол дазваляе вызначыць правілы ці інструкцыі для рэалізацыі класа, таму давайце падумаем, якімі яны мусяць быць. Усяго трэба чатыры.
Пачатак гульні: memoryGameDidStart.
Трэба перавярнуць картку кашуляй уніз: memoryGameShowCards.
Трэба перавярнуць картку кашуляй уверх: memoryGameHideCards.
Завяршэнне гульні: memoryGameDidEnd.
Усе чатыры метаду рэалізуемы для асноўнага класа, а гэта GameController.
memoryGameDidStart
Калі гэты метад запушчаны, гульня павінна пачацца (карыстальнік націскае PLAY). Тут проста перазагрузім кантэнт, выклікаўшы collectionView.reloadData (), што прывядзе да мяшання карт.
Выклікаем гэты метад з collectionSDViewSelectItemAt. Спачатку ён паказвае выбраную карту. Затым правярае, ці ёсць у масіве cardsShown несупастаўленая карта (калі лік cardsShown няцотны). Калі такая ёсць, абраная карта параўноўваецца з ёю. Калі карцінкі аднолькавыя, абедзве карты дадаюцца да cardsShown і застаюцца адкрытымі. Калі розныя, карта сыходзіць з cardsShown, і абедзве пераварочваюцца кашуляй уверх.
memoryGameHideCards
Калі карты не адпавядаюць адзін аднаму, выклікаецца гэты метад, і карцінкі картак хаваюцца.
shown = false.
memoryGameDidEnd
Калі выклікаецца гэты метад, азначае, што ўсе карты ўжо адчыненыя і знаходзяцца ў спісе cardsShown: cardsShown.count = cards.count, так што гульня скончана. Метад выклікаецца спецыяльна пасля таго, як мы выклікалі endGame (), каб усталяваць isPlaying var у false, пасля чаго паказваецца паведамленне аб завяршэнні гульні. Таксама alertController выкарыстоўваецца ў якасці індыкатара для кантролера. Выклікаецца viewDidDisappear і гульня скідаецца.
Вось як усё гэта выглядае ў 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()
}
}
Уласна, вось і ўсё. Вы можаце выкарыстоўваць гэты праект для стварэння ўласнага варыянта гульні.