Nulis Game Kartu Memori ing Swift

Nulis Game Kartu Memori ing Swift

Artikel iki njlèntrèhaké proses nggawe game latihan memori prasaja sing aku seneng banget. Saliyane apik, sampeyan bakal sinau luwih akeh babagan kelas lan protokol Swift nalika sampeyan lunga. Nanging sadurunge kita miwiti, ayo kang ngerti game dhewe.

Kita ngelingake: kanggo kabeh sing maca "Habr" - diskon 10 rubel nalika ndhaptar kursus Skillbox nggunakake kode promosi "Habr".

Skillbox nyaranake: Kursus online pendidikan "Profesi Java Developer".

Carane kanggo muter kertu memori

Game kasebut diwiwiti kanthi demonstrasi set kertu. Padha ngapusi madhep mudhun (mungguh, gambar mudhun). Nalika sampeyan ngeklik salah siji, gambar mbukak sawetara detik.

Tugas pamuter nemokake kabeh kertu kanthi gambar sing padha. Yen, sawise mbukak kertu pisanan, sampeyan nguripake liwat kaloro lan gambar cocog, loro kertu tetep mbukak. Yen padha ora cocog, kertu ditutup maneh. Tujuane kanggo mbukak kabeh.

Struktur proyek

Kanggo nggawe versi prasaja saka game iki sampeyan kudu komponen ing ngisor iki:

  • Siji Controller: GameController.swift.
  • Siji Tampilan: CardCell.swift.
  • Rong Model: MemoryGame.swift lan Card.swift.
  • Main.storyboard kanggo mesthekake yen kabeh pesawat saka komponen kasedhiya.

Kita miwiti karo komponen paling gampang saka game, kertu.

Card.swift

Model kertu bakal duwe telung sifat: id kanggo ngenali saben siji, variabel boolean sing dituduhake kanggo nemtokake status kertu (didhelikake utawa mbukak), lan artworkURL kanggo gambar ing kertu.

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

Sampeyan uga mbutuhake cara iki kanggo ngontrol interaksi pangguna karo peta:

Cara kanggo nampilake gambar ing kertu. Ing kene kita ngreset kabeh properti dadi standar. Kanggo id, kita generate id acak dening nelpon NSUUIS ().uuidString.

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

Cara kanggo mbandhingake KTP.

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

Cara nggawe salinan saben kertu - supaya entuk jumlah sing luwih akeh sing padha. Cara iki bakal ngasilake kertu kanthi nilai sing padha.

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

Lan siji cara liyane dibutuhake kanggo ngacak kertu ing wiwitan. Kita bakal nggawe extension saka kelas Array.

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

Lan iki implementasine kode kanggo model Card karo kabeh sifat lan cara.

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

Terusake.

Model kapindho yaiku MemoryGame, ing kene kita nyetel kothak 4 * 4. Model kasebut bakal duwe properti kayata kertu (sakumpulan kertu ing kothak), susunan kartu sing ditampilake karo kertu sing wis mbukak, lan variabel boolean isPlaying kanggo nglacak status game kasebut.

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

Kita uga kudu ngembangake cara kanggo ngontrol interaksi pangguna karo kothak.

A cara sing shuffles kertu ing kothak.

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

Cara nggawe game anyar. Kene kita nelpon cara pisanan kanggo miwiti tata letak dhisikan lan initialize variabel isPlaying kanggo bener.

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

Yen kita pengin miwiti maneh game, banjur kita nyetel variabel isPlaying palsu lan mbusak tata letak dhisikan saka kertu.

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

Cara kanggo verifikasi kertu sing diklik. Liyane babagan dheweke mengko.

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

Cara sing ngasilake posisi kertu tartamtu.

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

Priksa kepatuhan kertu sing dipilih karo standar.

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

Cara iki maca unsur pungkasan ing ** cardsShown ** Uploaded lan bali kertu non-cocog.

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

Main.storyboard katon kaya iki:

Nulis Game Kartu Memori ing Swift

Kaping pisanan, sampeyan kudu nyetel game anyar minangka viewDidLoad ing controller, kalebu gambar kanggo kothak. Ing game, kabeh iki bakal diwakili dening 4 * 4 collectionView. Yen sampeyan durung kenal karo collectionView, kene sampeyan bisa njaluk informasi sing dibutuhake.

Kita bakal ngatur GameController minangka pengontrol root aplikasi. GameController bakal duwe collectionView sing bakal kita rujuk minangka IBOutlet. Referensi liyane kanggo IBAction onStartGame () tombol, iki UIButton, sampeyan bisa ndeleng ing storyboard disebut PLAY.

A sethitik babagan implementasine saka controller:

  • First, kita initialize loro obyek utama - kothak: game = MemoryGame (), lan pesawat saka kertu: kertu = [Card] ().
  • Kita nyetel variabel awal minangka viewDidLoad, iki minangka cara pisanan sing diarani nalika game mlaku.
  • collectionView disetel kanggo didhelikake amarga kabeh kertu didhelikake nganti pangguna mencet PLAY.
  • Sanalika kita menet PLAY, miwiti bagean onStartGame IBAction, lan kita nyetel property collectionView isHidden palsu supaya kertu bisa katon.
  • Saben pangguna milih kertu, metode didSelectItemAt diarani. Ing cara kita nelpon didSelectCard kanggo ngleksanakake logika game utama.

Iki minangka implementasi GameController pungkasan:

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

Saiki ayo ngomong babagan protokol penting.

Protokol

Nggarap protokol minangka inti saka pemrograman Swift. Protokol nyedhiyakake kemampuan kanggo nemtokake aturan kanggo kelas, struktur, utawa enumerasi. Prinsip iki ngidini sampeyan nulis kode modular lan extensible. Nyatane, iki minangka pola sing wis ditindakake kanggo collectionView ing GameController. Saiki ayo nggawe versi kita dhewe. Sintaks bakal katon kaya iki:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Kita ngerti manawa protokol ngidini kita nemtokake aturan utawa instruksi kanggo ngetrapake kelas, mula ayo dipikirake apa sing kudu ditindakake. Sampeyan butuh papat total.

  • Game wiwitan: memoryGameDidStart.
  • Sampeyan kudu nguripake kertu mudhun: memoryGameShowCards.
  • Sampeyan kudu nguripake kertu mudhun: memoryGameHideCards.
  • Game pungkasan: memoryGameDidEnd.

Kabeh papat cara bisa dileksanakake kanggo kelas utama, yaiku GameController.

memoriGameDidStart

Nalika cara iki mbukak, game kudu miwiti (pangguna mencet PLAY). Kene kita mung bakal isi maneh kanthi nelpon collectionView.reloadData (), sing bakal ngacak kertu.

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

memoryGameShowCard

Kita nelpon cara iki saka collectionSDViewSelectItemAt. Pisanan nuduhake kertu sing dipilih. Banjur mriksa kanggo ndeleng yen ana kertu sing ora cocog ing array cardsShown (yen jumlah cardsShown aneh). Yen ana siji, kertu sing dipilih dibandhingake karo. Yen gambar padha, loro kertu ditambahake menyang cardsShown lan tetep madhep munggah. Yen beda, kertu ninggalake cardsShown lan loro-lorone dipateni.

memoryGameHideCards

Yen kertu ora cocog, cara iki diarani lan gambar kertu didhelikake.

dituduhake = palsu.

memoriGameDidEnd

Nalika cara iki disebut, iku tegese kabeh SIM wis dicethakakΓ© ana ing dhaftar cardsShown: cardsShown.count = cards.count, supaya game wis rampung. Cara disebut khusus sawise kita wis disebut endGame () kanggo nyetel isPlaying var palsu, sawise pesen game pungkasan ditampilake. Uga alertController digunakake minangka indikator kanggo controller. viewDidDisappear diarani lan game direset.

Mangkene kabeh katon ing 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()
    }
}

Nulis Game Kartu Memori ing Swift
Bener, iku kabeh. Sampeyan bisa nggunakake proyek iki kanggo nggawe versi game dhewe.

Sugeng coding!

Skillbox nyaranake:

Source: www.habr.com

Add a comment