Swift-də Yaddaş Kartları Oyununun Yazılması

Swift-də Yaddaş Kartları Oyununun Yazılması

Bu məqalə mənim çox bəyəndiyim sadə yaddaş təlimi oyununun yaradılması prosesini təsvir edir. Özlüyündə yaxşı olmaqdan əlavə, getdikcə Swift dərsləri və protokolları haqqında bir az daha çox öyrənəcəksiniz. Ancaq başlamazdan əvvəl oyunun özünü anlayaq.

Xatırladırıq: "Habr" ın bütün oxucuları üçün - "Habr" promosyon kodundan istifadə edərək hər hansı bir Skillbox kursuna yazılarkən 10 000 rubl endirim.

Skillbox tövsiyə edir: Onlayn təhsil kursu "Peşə Java Developer".

Yaddaş Kartını necə oynamaq olar

Oyun bir sıra kartların nümayişi ilə başlayır. Üzüstə uzanırlar (müvafiq olaraq, şəkil aşağı). Hər hansı birinin üzərinə kliklədiyiniz zaman şəkil bir neçə saniyə ərzində açılır.

Oyunçunun vəzifəsi eyni şəkilləri olan bütün kartları tapmaqdır. Birinci kartı açdıqdan sonra ikincini çevirsəniz və şəkillər uyğun gəlsə, hər iki kart açıq qalır. Əgər onlar uyğun gəlmirsə, kartlar yenidən bağlanır. Məqsəd hər şeyi açmaqdır.

Layihə strukturu

Bu oyunun sadə versiyasını yaratmaq üçün sizə aşağıdakı komponentlər lazımdır:

  • Bir Nəzarətçi: GameController.swift.
  • Bir Görünüş: CardCell.swift.
  • İki Model: MemoryGame.swift və Card.swift.
  • Bütün komponentlər dəstinin mövcud olmasını təmin etmək üçün Main.storyboard.

Oyunun ən sadə komponenti olan kartlardan başlayırıq.

Card.swift

Kart modelinin üç xassələri olacaq: hər birini müəyyən etmək üçün id, kartın statusunu təyin etmək üçün göstərilən mantiq dəyişəni (gizli və ya açıq) və kartlardakı şəkillər üçün artworkURL.

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

İstifadəçinin xəritələrlə qarşılıqlı əlaqəsini idarə etmək üçün sizə bu üsullara da ehtiyacınız olacaq:

Kartda təsvirin göstərilməsi üsulu. Burada bütün xassələri standart vəziyyətə qaytarırıq. İd üçün NSUUIS().uuidString zəng edərək təsadüfi id yaradırıq.

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

Şəxsiyyət vəsiqələrinin müqayisəsi üsulu.

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

Hər kartın surətini yaratmaq üsulu - daha çox sayda eyni olanları əldə etmək üçün. Bu üsul oxşar dəyərlərə malik kartı qaytaracaq.

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

Və başlanğıcda kartları qarışdırmaq üçün daha bir üsul lazımdır. Biz onu Array sinifinin uzantısına çevirəcəyik.

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

Və burada bütün xassələri və üsulları ilə Kart modeli üçün kodun həyata keçirilməsi.

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() }
        }
    }
}

Durmayın.

İkinci model MemoryGame-dir, burada biz 4*4 şəbəkə qurduq. Model kartlar (torda olan kartlar massivi), artıq açıq kartları olan cardsShown massivi və oyunun statusunu izləmək üçün isPlaying boolean dəyişəni kimi xüsusiyyətlərə malik olacaq.

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

Biz həmçinin istifadəçinin şəbəkə ilə qarşılıqlı əlaqəsini idarə etmək üçün metodlar hazırlamalıyıq.

Bir şəbəkədə kartları qarışdıran bir üsul.

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

Yeni oyun yaratmaq üçün üsul. Burada ilkin tərtibata başlamaq və isPlaying dəyişənini doğru olaraq işə salmaq üçün birinci metodu çağırırıq.

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

Oyunu yenidən başlamaq istəyiriksə, sonra isPlaying dəyişənini false olaraq təyin etdik və kartların ilkin tərtibatını sildik.

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

Kliklənmiş kartların yoxlanılması üsulu. Onun haqqında daha sonra.

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

Müəyyən bir kartın mövqeyini qaytaran bir üsul.

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

Seçilmiş kartın standarta uyğunluğunun yoxlanılması.

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

Bu üsul **cardsShown** massivindəki sonuncu elementi oxuyur və uyğun olmayan kartı qaytarır.

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 və GameController.swift

Main.storyboard belə görünür:

Swift-də Yaddaş Kartları Oyununun Yazılması

Əvvəlcə yeni oyunu, şəbəkə üçün şəkillər də daxil olmaqla, nəzarətçidə viewDidLoad kimi təyin etməlisiniz. Oyunda bütün bunlar 4*4 collectionView ilə təmsil olunacaq. CollectionView ilə hələ tanış deyilsinizsə, budur lazım olan məlumatları əldə edə bilərsiniz.

Biz GameController-i proqramın kök nəzarətçisi kimi konfiqurasiya edəcəyik. GameController-də IBOutlet kimi istinad edəcəyimiz kolleksiya Görünüşü olacaq. Başqa bir istinad IBAction onStartGame() düyməsidir, bu UIButtondur, siz onu PLAY adlı hekayə lövhəsində görə bilərsiniz.

Nəzarətçilərin tətbiqi haqqında bir az:

  • Əvvəlcə iki əsas obyekti işə salırıq - şəbəkə: oyun = MemoryGame() və bir sıra kartlar: kartlar = [Kart]().
  • İlkin dəyişənləri viewDidLoad olaraq təyin etdik, bu, oyun işləyərkən çağırılan ilk üsuldur.
  • collectionView gizli olaraq təyin edilib, çünki istifadəçi PLAY düyməsini basana qədər bütün kartlar gizlədilir.
  • PLAY düyməsini basan kimi onStartGame IBAction bölməsi başlayır və biz collectionView isHidden xüsusiyyətini false olaraq təyin edirik ki, kartların görünməsi mümkün olsun.
  • İstifadəçi hər dəfə kartı seçəndə didSelectItemAt metodu çağırılır. Əsas oyun məntiqini həyata keçirmək üçün didSelectCard adlandırdığımız metodda.

Budur son GameController tətbiqi:

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)
    }
}

İndi vacib protokollar haqqında bir az danışaq.

Protokollar

Protokollarla işləmək Swift proqramlaşdırmasının əsasını təşkil edir. Protokollar sinif, struktur və ya siyahıyaalma üçün qaydaları müəyyən etmək imkanı verir. Bu prinsip modul və genişləndirilə bilən kodu yazmağa imkan verir. Əslində, bu, GameController-də collectionView üçün artıq tətbiq etdiyimiz nümunədir. İndi öz versiyamızı yaradaq. Sintaksis belə görünəcək:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Biz bilirik ki, protokol bizə bir sinfi həyata keçirmək üçün qaydaları və ya təlimatları müəyyən etməyə imkan verir, ona görə də onların nə olması lazım olduğunu düşünək. Sizə cəmi dörd lazımdır.

  • Oyunun başlanğıcı: yaddaşGameDidStart.
  • Siz kartı üzü aşağı çevirməlisiniz: memoryGameShowCards.
  • Kartın üzünü aşağı çevirməlisiniz: memoryGameHideCards.
  • Oyunun sonu: yaddaşGameDidEnd.

Bütün dörd üsul GameController olan əsas sinif üçün həyata keçirilə bilər.

yaddaşGameDidStart

Bu üsul işə salındıqda oyun başlamalıdır (istifadəçi PLAY düyməsini basır). Burada sadəcə olaraq, kartları qarışdıracaq collectionView.reloadData() çağıraraq məzmunu yenidən yükləyəcəyik.

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

yaddaşGameShowCards

Biz bu metodu collectionSDViewSelectItemAt-dan çağırırıq. Əvvəlcə seçilmiş kartı göstərir. Sonra cardsShown massivində (göstərilən kartların sayı təkdirsə) bənzərsiz kartın olub olmadığını yoxlayır. Əgər varsa, seçilmiş kart onunla müqayisə edilir. Şəkillər eyni olarsa, hər iki kart Göstərilən kartlara əlavə edilir və üzü yuxarı qalır. Əgər fərqlidirsə, kart kartları Göstərilir və hər ikisi üzü aşağı çevrilir.

yaddaşGameGameCards

Kartlar uyğun gəlmirsə, bu üsul çağırılır və kart şəkilləri gizlədilir.

göstərilir = yalan.

yaddaşGameDidEnd

Bu üsul çağırıldıqda, bu, bütün kartların artıq aşkar edildiyini və kartların Göstərilən siyahısında olduğunu bildirir: cardsShown.count = cards.count, beləliklə, oyun bitdi. Metod xüsusi olaraq isPlaying var parametrini false kimi təyin etmək üçün endGame() funksiyasını çağırdıqdan sonra çağırılır, bundan sonra oyunun bitmə mesajı göstərilir. Həmçinin alertController nəzarətçi üçün göstərici kimi istifadə olunur. viewDidDisappear çağırılır və oyun yenidən qurulur.

GameController-də hər şey belə görünür:

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()
    }
}

Swift-də Yaddaş Kartları Oyununun Yazılması
Əslində, hamısı budur. Oyunun öz versiyasını yaratmaq üçün bu layihədən istifadə edə bilərsiniz.

Xoşbəxt kodlaşdırma!

Skillbox tövsiyə edir:

Mənbə: www.habr.com

Добавить комментарий