Свифт дээр санах ойн картын тоглоом бичих

Свифт дээр санах ойн картын тоглоом бичих

Энэ нийтлэлд надад үнэхээр таалагддаг энгийн санах ойн сургалтын тоглоом бүтээх үйл явцыг тайлбарласан болно. Та өөрөө сайн байхаас гадна Свифтийн анги, протоколын талаар бага зэрэг сурах болно. Гэхдээ эхлэхээсээ өмнө тоглоомыг өөрөө ойлгоцгооё.

Бид танд сануулж байна: "Хабр" -ын бүх уншигчдад - "Habr" сурталчилгааны кодыг ашиглан Skillbox-ын аль ч курст бүртгүүлэхдээ 10 рублийн хөнгөлөлт.

Skillbox зөвлөж байна: Боловсролын онлайн курс "Мэргэжил Java хөгжүүлэгч".

Санах ойн картыг хэрхэн тоглох вэ

Тоглоом нь багц картуудыг үзүүлснээр эхэлдэг. Тэд нүүрээ харан хэвтдэг (тус тусад нь зураг доошоо). Аль нэг дээр нь дарахад зураг хэдхэн секундын турш нээгдэнэ.

Тоглогчийн даалгавар бол ижил зурагтай бүх картыг олох явдал юм. Хэрэв та эхний картыг нээсний дараа хоёр дахь картыг эргүүлж, зураг таарч байвал хоёр карт нээлттэй хэвээр байна. Хэрэв тэдгээр нь таарахгүй бол картууд дахин хаагдана. Зорилго нь бүх зүйлийг нээх явдал юм.

Төслийн бүтэц

Энэ тоглоомын энгийн хувилбарыг бий болгохын тулд танд дараах бүрэлдэхүүн хэсгүүд хэрэгтэй болно.

  • Нэг хянагч: GameController.swift.
  • Нэг харах: CardCell.swift.
  • Хоёр загвар: MemoryGame.swift болон Card.swift.
  • Бүхэл бүтэн бүрэлдэхүүн хэсгүүд бэлэн байгаа эсэхийг баталгаажуулахын тулд Main.storyboard.

Бид тоглоомын хамгийн энгийн бүрэлдэхүүн хэсэг болох хөзрөөс эхэлдэг.

Card.swift

Картын загвар нь тус бүрийг таних id, картын статусыг зааж өгөх логикийн хувьсагч (далд эсвэл нээлттэй) болон карт дээрх зургуудад зориулсан artworkURL гэсэн гурван шинж чанартай байх болно.

class Card {        
    var id: String    
    var shown: Bool = false    
    var artworkURL: UIImage!
}

Хэрэглэгчийн газрын зурагтай харилцах харилцааг хянахын тулд танд дараах аргууд хэрэгтэй болно:

Картан дээрх зургийг харуулах арга. Энд бид бүх шинж чанарыг анхдагч болгож тохируулна. ID-ийн хувьд бид NSUUIS().uuidString руу залгаж санамсаргүй id үүсгэдэг.

init(image: UIImage) {        
    self.id = NSUUID().uuidString        
    self.shown = false        
    self.artworkURL = image    
}

Иргэний үнэмлэхийг харьцуулах арга.

func equals(_ card: Card) -> Bool {
    return (card.id == id)    
}

Карт бүрийн хуулбарыг үүсгэх арга - илүү олон тооны ижил төстэй зүйлийг авахын тулд. Энэ арга нь ижил утгатай картыг буцаана.

func copy() -> Card {        
    return Card(card: self)    
}
 
init(card: Card) {        
    self.id = card.id        
    self.shown = card.shown        
    self.artworkURL = card.artworkURL    
}

Мөн эхэнд картуудыг холихын тулд өөр нэг арга хэрэгтэй. Бид үүнийг Array ангийн өргөтгөл болгох болно.

extension Array {    
    mutating func shuffle() {        
        for _ in 0...self.count {            
            sort { (_,_) in arc4random() < arc4random() }        
        }   
    }
}

Мөн энд бүх шинж чанар, аргуудтай Картын загварт зориулсан кодын хэрэгжилт энд байна.

class Card {
    
    var id: String
    var shown: Bool = false
    var artworkURL: UIImage!
    
    static var allCards = [Card]()
 
    init(card: Card) {
        self.id = card.id
        self.shown = card.shown
        self.artworkURL = card.artworkURL
    }
    
    init(image: UIImage) {
        self.id = NSUUID().uuidString
        self.shown = false
        self.artworkURL = image
    }
    
    func equals(_ card: Card) -> Bool {
        return (card.id == id)
    }
    
    func copy() -> Card {
        return Card(card: self)
    }
}
 
extension Array {
    mutating func shuffle() {
        for _ in 0...self.count {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}

Явцгаая.

Хоёрдахь загвар нь MemoryGame, энд бид 4*4 сүлжээг тавьсан. Энэхүү загвар нь картууд (сүлжээ дээрх картуудын массив), аль хэдийн нээгдсэн карт бүхий картуудShown массив, тоглоомын статусыг хянах логикийн хувьсагч isPlaying зэрэг шинж чанаруудтай байх болно.

class MemoryGame {        
    var cards:[Card] = [Card]()    
    var cardsShown:[Card] = [Card]()    
    var isPlaying: Bool = false
}

Мөн бид сүлжээтэй хэрэглэгчийн харилцааг хянах аргуудыг боловсруулах хэрэгтэй.

Сүлжээнд картуудыг холих арга.

func shuffleCards(cards:[Card]) -> [Card] {       
    var randomCards = cards        
    randomCards.shuffle()                
 
    return randomCards    
}

Шинэ тоглоом үүсгэх арга. Энд бид эхний байрлалыг эхлүүлэх, isPlaying хувьсагчийг үнэн болгох эхний аргыг дуудна.

func newGame(cardsArray:[Card]) -> [Card] {       
    cards = shuffleCards(cards: cardsArray)        
    isPlaying = true            
 
    return cards    
}

Хэрэв бид тоглоомоо дахин эхлүүлэхийг хүсвэл дараа нь бид isPlaying хувьсагчийг худал болгож, картуудын анхны байршлыг устгана.

func restartGame() {        
    isPlaying = false                
    cards.removeAll()        
    cardsShown.removeAll()    
}

Товшсон картуудыг шалгах арга. Түүний тухай дараа дэлгэрэнгүй.

func cardAtIndex(_ index: Int) -> Card? {        
    if cards.count > index {            
        return cards[index]        
    } else {            
        return nil        
    }    
}

Тодорхой картын байрлалыг буцаадаг арга.

func indexForCard(_ card: Card) -> Int? {        
    for index in 0...cards.count-1 {            
        if card === cards[index] {                
            return index            
        }      
    }
        
    return nil    
}

Сонгосон карт нь стандартад нийцэж байгаа эсэхийг шалгах.

func unmatchedCardShown() -> Bool {
    return cardsShown.count % 2 != 0
}

Энэ арга нь **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 нэртэй storyboard дээрээс харж болно.

Хянагчдыг хэрэгжүүлэх талаар бага зэрэг:

  • Эхлээд бид хоёр үндсэн объектыг эхлүүлнэ - сүлжээ: тоглоом = MemoryGame(), картуудын багц: карт = [Карт]().
  • Бид анхны хувьсагчдыг viewDidLoad гэж тохируулсан бөгөөд энэ нь тоглоом ажиллаж байх үед дуудагддаг анхны арга юм.
  • Хэрэглэгч PLAY товчлуурыг дарах хүртэл бүх картууд нуугдсан тул collectionView-г нуугдмал гэж тохируулсан.
  • PLAY товчийг дармагц onStartGame IBAction хэсэг эхлэх ба бид collectionView isHidden шинж чанарыг худал болгож, картууд харагдах болно.
  • Хэрэглэгч карт сонгох бүрт didSelectItemAt аргыг дууддаг. Тоглоомын үндсэн логикийг хэрэгжүүлэхийн тулд бид didSelectCard гэж нэрлэдэг.

GameController-ийн эцсийн хэрэгжилт энд байна:

class GameController: UIViewController {
 
    @IBOutlet weak var collectionView: UICollectionView!
    
    let game = MemoryGame()
    var cards = [Card]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        game.delegate = self
        
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.isHidden = true
        
        APIClient.shared.getCardImages { (cardsArray, error) in
            if let _ = error {
                // show alert
            }
            
            self.cards = cardsArray!
            self.setupNewGame()
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        if game.isPlaying {
            resetGame()
        }
    }
    
    func setupNewGame() {
        cards = game.newGame(cardsArray: self.cards)
        collectionView.reloadData()
    }
    
    func resetGame() {
        game.restartGame()
        setupNewGame()
    }
    
    @IBAction func onStartGame(_ sender: Any) {
        collectionView.isHidden = false
    }
}
 
// MARK: - CollectionView Delegate Methods
extension GameController: UICollectionViewDelegate, UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return cards.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CardCell", for: indexPath) as! CardCell
        cell.showCard(false, animted: false)
        
        guard let card = game.cardAtIndex(indexPath.item) else { return cell }
        cell.card = card
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath) as! CardCell
        
        if cell.shown { return }
        game.didSelectCard(cell.card)
        
        collectionView.deselectItem(at: indexPath, animated:true)
    }
}

Одоо чухал протоколуудын талаар бага зэрэг яръя.

Протокол

Протоколуудтай ажиллах нь Swift програмчлалын гол цөм юм. Протоколууд нь анги, бүтэц, тооллогын дүрмийг тодорхойлох боломжийг олгодог. Энэ зарчим нь модульчлагдсан, өргөтгөх боломжтой код бичих боломжийг олгодог. Үнэн хэрэгтээ энэ бол бидний GameController дээр collectionView-д зориулж аль хэдийн хэрэгжүүлж байгаа загвар юм. Одоо өөрсдийнхөө хувилбарыг хийцгээе. Синтакс нь дараах байдлаар харагдах болно.

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Протокол нь анги хэрэгжүүлэх дүрэм, зааврыг тодорхойлох боломжийг олгодог гэдгийг бид мэдэж байгаа тул тэдгээр нь ямар байх ёстойг бодоцгооё. Танд нийт дөрөв хэрэгтэй.

  • Тоглоомын эхлэл: memoryGameDidStart.
  • Та картыг доош нь эргүүлэх хэрэгтэй: memoryGameShowCards.
  • Та картыг доош нь эргүүлэх хэрэгтэй: memoryGameHideCards.
  • Тоглоомын төгсгөл: memoryGameDidEnd.

Бүх дөрвөн аргыг үндсэн анги болох GameController-д ашиглаж болно.

memoryGameDidStart

Энэ аргыг ажиллуулахад тоглоом эхлэх ёстой (хэрэглэгч PLAY дээр дарна). Энд бид CollectionView.reloadData() руу залгаж контентыг дахин ачаалах бөгөөд энэ нь картуудыг холих болно.

func memoryGameDidStart(_ game: MemoryGame) {
    collectionView.reloadData()
}

санах ойнGameShowCards

Бид CollectionSDViewSelectItemAt-аас энэ аргыг дууддаг. Эхлээд сонгосон картыг харуулна. Дараа нь cardsShown массив дотор тохирохгүй карт байгаа эсэхийг шалгана (ХэрэвShown картын тоо сондгой бол). Хэрэв байгаа бол сонгосон картыг түүнтэй харьцуулна. Хэрэв зургууд ижил байвал хоёр картыг харуулах картуудад нэмж, нүүрээ дээш харуулна. Хэрэв өөр бол карт нь картуудыг харуулах бөгөөд хоёуланг нь доош харуулна.

санах ойнGameHideCards

Хэрэв картууд таарахгүй бол энэ аргыг дуудаж, картын зургуудыг нууна.

харуулсан = худал.

санах ойнGameDidEnd

Энэ аргыг дуудах үед бүх картууд аль хэдийн илэрсэн бөгөөд cardsShown жагсаалтад байгаа гэсэн үг юм: cardsShown.count = cards.count, тэгэхээр тоглоом дууссан. Бид isPlaying var-г худал болгохын тулд endGame()-г дуудсаны дараа уг аргыг тусгайлан дууддаг бөгөөд үүний дараа тоглоомын төгсгөлийн мессеж гарч ирнэ. Мөн 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()
    }
}

Свифт дээр санах ойн картын тоглоом бичих
Үнэндээ бол энэ л байна. Та энэ төслийг ашиглан тоглоомын өөрийн хувилбарыг үүсгэж болно.

Аз жаргалтай кодчилол!

Skillbox зөвлөж байна:

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх