Menulis Permainan Kartu Memori di Swift

Menulis Permainan Kartu Memori di Swift

Artikel ini menjelaskan proses pembuatan game pelatihan memori sederhana yang sangat saya sukai. Selain menjadi ahli dalam hal itu sendiri, Anda akan belajar lebih banyak tentang kelas dan protokol Swift seiring berjalannya waktu. Namun sebelum kita mulai, mari kita pahami game itu sendiri.

Kami mengingatkan: untuk semua pembaca "Habr" - diskon 10 rubel saat mendaftar di kursus Skillbox apa pun menggunakan kode promosi "Habr".

Skillbox merekomendasikan: Kursus online pendidikan "Profesi Pengembang Java".

Cara memainkan Kartu Memori

Permainan dimulai dengan peragaan satu set kartu. Mereka berbaring telungkup (masing-masing, gambar ke bawah). Saat Anda mengeklik salah satunya, gambar akan terbuka selama beberapa detik.

Tugas pemain adalah menemukan semua kartu dengan gambar yang sama. Jika setelah membuka kartu pertama, Anda membalik kartu kedua dan gambarnya cocok, kedua kartu tetap terbuka. Jika tidak cocok, kartu ditutup kembali. Tujuannya adalah untuk membuka segalanya.

Struktur proyek

Untuk membuat versi sederhana game ini Anda memerlukan komponen berikut:

  • Satu Pengontrol: GameController.swift.
  • Satu Tampilan: CardCell.swift.
  • Dua Model: MemoryGame.swift dan Card.swift.
  • Main.storyboard untuk memastikan bahwa seluruh rangkaian komponen tersedia.

Kita mulai dengan komponen permainan yang paling sederhana, yaitu kartu.

Kartu.cepat

Model kartu akan memiliki tiga properti: id untuk mengidentifikasi masing-masing properti, variabel boolean yang ditampilkan untuk menentukan status kartu (tersembunyi atau terbuka), dan artworkURL untuk gambar pada kartu.

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

Anda juga memerlukan metode berikut untuk mengontrol interaksi pengguna dengan peta:

Metode untuk menampilkan gambar pada kartu. Di sini kami mengatur ulang semua properti ke default. Untuk id, kami membuat id acak dengan memanggil NSUIS().uuidString.

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

Metode perbandingan KTP.

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

Metode untuk membuat salinan setiap kartu - untuk mendapatkan jumlah yang identik lebih banyak. Metode ini akan mengembalikan kartu dengan nilai serupa.

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

Dan diperlukan satu cara lagi untuk mengocok kartu di awal. Kami akan menjadikannya perpanjangan dari kelas Array.

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

Dan berikut adalah implementasi kode untuk model Card dengan semua properti dan metodenya.

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

Lanjutkan.

Model kedua adalah MemoryGame, di sini kita menetapkan grid 4*4. Model akan memiliki properti seperti cards (array kartu pada grid), array cardsShown dengan kartu sudah terbuka, dan variabel boolean isPlaying untuk melacak status permainan.

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

Kita juga perlu mengembangkan metode untuk mengontrol interaksi pengguna dengan jaringan listrik.

Sebuah metode yang mengocok kartu dalam kotak.

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

Metode untuk membuat game baru. Di sini kita memanggil metode pertama untuk memulai tata letak awal dan menginisialisasi variabel isPlaying ke true.

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

Jika kita ingin memulai kembali permainan, lalu kita atur variabel isPlaying ke false dan hapus tata letak awal kartu.

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

Metode untuk memverifikasi kartu yang diklik. Lebih lanjut tentang dia nanti.

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

Sebuah metode yang mengembalikan posisi kartu tertentu.

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

Memeriksa kesesuaian kartu yang dipilih dengan standar.

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

Metode ini membaca elemen terakhir dalam array **cardsShown** dan mengembalikan kartu yang tidak cocok.

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 dan GameController.swift

Main.storyboard terlihat seperti ini:

Menulis Permainan Kartu Memori di Swift

Awalnya, Anda perlu menyetel game baru sebagai viewDidLoad di pengontrol, termasuk gambar untuk grid. Di dalam game, semua ini akan diwakili oleh 4*4 collectionView. Jika Anda belum familiar dengan collectionView, ini dia Anda bisa mendapatkan informasi yang Anda butuhkan.

Kami akan mengkonfigurasi GameController sebagai pengontrol root aplikasi. GameController akan memiliki collectionView yang akan kita referensikan sebagai IBOutlet. Referensi lainnya adalah tombol IBAction onStartGame(), ini adalah UIButton, Anda dapat melihatnya di storyboard bernama PLAY.

Sedikit tentang implementasi pengontrol:

  • Pertama, kita menginisialisasi dua objek utama - grid: game = MemoryGame(), dan satu set kartu: cards = [Card]().
  • Kami menetapkan variabel awal sebagai viewDidLoad, ini adalah metode pertama yang dipanggil saat game sedang berjalan.
  • collectionView disetel ke tersembunyi karena semua kartu disembunyikan hingga pengguna menekan PLAY.
  • Segera setelah kita menekan PLAY, bagian onStartGame IBAction dimulai, dan kita menyetel properti collectionView isHidden ke false sehingga kartu dapat terlihat.
  • Setiap kali pengguna memilih kartu, metode didSelectItemAt dipanggil. Dalam metode ini kami memanggil didSelectCard untuk mengimplementasikan logika permainan utama.

Berikut adalah implementasi terakhir 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)
    }
}

Sekarang mari kita bicara sedikit tentang protokol penting.

Protokol

Bekerja dengan protokol adalah inti dari pemrograman Swift. Protokol menyediakan kemampuan untuk mendefinisikan aturan untuk kelas, struktur, atau enumerasi. Prinsip ini memungkinkan Anda menulis kode modular dan dapat diperluas. Faktanya, ini adalah pola yang sudah kami terapkan untuk collectionView di GameController. Sekarang mari kita buat versi kita sendiri. Sintaksnya akan terlihat seperti ini:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Kita tahu bahwa protokol memungkinkan kita untuk menentukan aturan atau instruksi untuk mengimplementasikan suatu kelas, jadi mari kita pikirkan apa yang seharusnya. Anda membutuhkan total empat.

  • Permainan dimulai: memoryGameDidStart.
  • Anda perlu membalikkan kartunya: memoryGameShowCards.
  • Anda perlu membalikkan kartunya: memoryGameHideCards.
  • Permainan berakhir: memoryGameDidEnd.

Keempat metode tersebut dapat diimplementasikan untuk kelas utama, yaitu GameController.

memoriGameDidStart

Ketika metode ini dijalankan, permainan akan dimulai (pengguna menekan PLAY). Di sini kita cukup memuat ulang konten dengan memanggil collectionView.reloadData(), yang akan mengacak kartu.

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

memoriGameShowCards

Kami memanggil metode ini dari collectionSDViewSelectItemAt. Pertama, ini menunjukkan kartu yang dipilih. Kemudian periksa apakah ada kartu yang tidak cocok dalam array cardsShown (jika jumlah kartuShown ganjil). Jika ada, kartu yang dipilih dibandingkan dengannya. Jika gambarnya sama, kedua kartu ditambahkan ke kartu yang Ditampilkan dan tetap menghadap ke atas. Jika berbeda, kartu akan meninggalkan kartu Tampil dan keduanya menghadap ke bawah.

memoriGameHideCards

Jika kartu tidak cocok, metode ini dipanggil dan gambar kartu disembunyikan.

ditampilkan = salah.

memoriGameDidEnd

Ketika metode ini dipanggil, berarti semua kartu sudah terungkap dan ada di daftar cardsShown: cardsShown.count = cards.count, sehingga permainan selesai. Metode ini dipanggil secara khusus setelah kita memanggil endGame() untuk menyetel var isPlaying ke false, setelah itu pesan akhir permainan ditampilkan. AlertController juga digunakan sebagai indikator untuk pengontrol. viewDidDisappear dipanggil dan game direset.

Berikut tampilannya di 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()
    }
}

Menulis Permainan Kartu Memori di Swift
Sebenarnya, itu saja. Anda dapat menggunakan proyek ini untuk membuat versi game Anda sendiri.

Selamat membuat kode!

Skillbox merekomendasikan:

Sumber: www.habr.com

Tambah komentar