Shkrimi i një loje me karta memorie në Swift

Shkrimi i një loje me karta memorie në Swift

Ky artikull përshkruan procesin e krijimit të një loje të thjeshtë të trajnimit të kujtesës që më pëlqen shumë. Përveçse është i mirë në vetvete, do të mësoni pak më shumë për klasat dhe protokollet e Swift ndërsa shkoni. Por para se të fillojmë, le të kuptojmë vetë lojën.

Kujtojmë: për të gjithë lexuesit e "Habr" - një zbritje prej 10 rubla kur regjistroheni në çdo kurs Skillbox duke përdorur kodin promovues "Habr".

Skillbox rekomandon: Kurs edukativ online "Profesioni zhvillues Java".

Si të luani kartën e kujtesës

Loja fillon me një demonstrim të një grupi letrash. Ata shtrihen me fytyrë poshtë (përkatësisht, imazhi poshtë). Kur klikoni mbi ndonjë, imazhi hapet për disa sekonda.

Detyra e lojtarit është të gjejë të gjitha kartat me të njëjtat fotografi. Nëse, pas hapjes së kartës së parë, e ktheni të dytën dhe figurat përputhen, të dyja letrat mbeten të hapura. Nëse nuk përputhen, kartat mbyllen përsëri. Qëllimi është të hapim gjithçka.

Struktura e projektit

Për të krijuar një version të thjeshtë të kësaj loje ju nevojiten komponentët e mëposhtëm:

  • Një kontrollues: GameController.swift.
  • Një pamje: CardCell.swift.
  • Dy modele: MemoryGame.swift dhe Card.swift.
  • Main.storyboard për të siguruar që i gjithë grupi i komponentëve është i disponueshëm.

Ne fillojmë me komponentin më të thjeshtë të lojës, kartat.

Kartë.swift

Modeli i kartës do të ketë tre veti: id për të identifikuar secilën prej tyre, një variabël boolean që shfaqet për të specifikuar statusin e kartës (e fshehur ose e hapur) dhe artworkURL për imazhet në karta.

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

Do t'ju duhen gjithashtu këto metoda për të kontrolluar ndërveprimin e përdoruesve me hartat:

Metoda për shfaqjen e një imazhi në një kartë. Këtu i rivendosim të gjitha vetitë në parazgjedhje. Për id, ne gjenerojmë një id të rastësishëm duke thirrur NSUUIS().uuidString.

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

Metoda për krahasimin e kartave të identitetit.

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

Mënyra për të krijuar një kopje të secilës kartë - për të marrë një numër më të madh identike. Kjo metodë do të kthejë kartën me vlera të ngjashme.

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

Dhe një metodë tjetër nevojitet për të përzier letrat në fillim. Ne do ta bëjmë atë një zgjatim të klasës Array.

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

Dhe këtu është zbatimi i kodit për modelin e Kartës me të gjitha vetitë dhe metodat.

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

Leviz.

Modeli i dytë është MemoryGame, këtu kemi vendosur një rrjet 4*4. Modeli do të ketë veçori të tilla si kartat (një grup letrash në një rrjet), një grup kartash të shfaqura me karta tashmë të hapura dhe një variabël boolean është duke luajtur për të gjurmuar statusin e lojës.

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

Ne gjithashtu duhet të zhvillojmë metoda për të kontrolluar ndërveprimin e përdoruesit me rrjetin.

Një metodë që përzien kartat në një rrjet.

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

Metoda për krijimin e një loje të re. Këtu thërrasim metodën e parë për të nisur paraqitjen fillestare dhe për të inicializuar variablin isPlaying në true.

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

Nëse duam të rifillojmë lojën, pastaj e vendosim variablin isPlaying në false dhe heqim paraqitjen fillestare të kartave.

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

Metoda për verifikimin e kartave të klikuara. Më shumë rreth tij më vonë.

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

Një metodë që kthen pozicionin e një karte specifike.

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

Kontrollimi i përputhshmërisë së kartës së zgjedhur me standardin.

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

Kjo metodë lexon elementin e fundit në grupin **cardsShown** dhe kthen kartën që nuk përputhet.

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

Main.storyboard duket diçka si kjo:

Shkrimi i një loje me karta memorie në Swift

Fillimisht, duhet të vendosni lojën e re si viewDidLoad në kontrollues, duke përfshirë imazhet për rrjetin. Në lojë, e gjithë kjo do të përfaqësohet nga një koleksion View 4*4. Nëse nuk jeni njohur ende me collectionView, ja ku është ju mund të merrni informacionin që ju nevojitet.

Ne do të konfigurojmë GameController si kontrolluesin rrënjë të aplikacionit. GameController do të ketë një koleksionView të cilit do t'i referohemi si një IBOutlet. Një referencë tjetër është te butoni IBAction onStartGame(), ky është një buton UIB, mund ta shihni në skenën e tregimit të quajtur PLAY.

Pak për zbatimin e kontrollorëve:

  • Së pari, ne inicializojmë dy objekte kryesore - rrjetin: lojë = MemoryGame(), dhe një grup letrash: karta = [Card]().
  • Variablat fillestarë i vendosim si viewDidLoad, kjo është metoda e parë që thirret gjatë ekzekutimit të lojës.
  • collectionView është vendosur si i fshehur sepse të gjitha kartat janë të fshehura derisa përdoruesi të shtypë PLAY.
  • Sapo shtypim PLAY, fillon seksioni onStartGame IBAction dhe e vendosim vetinë collectionView isHidden në false në mënyrë që kartat të bëhen të dukshme.
  • Sa herë që përdoruesi zgjedh një kartë, thirret metoda didSelectItemAt. Në metodën që ne quajmë didSelectCard për të zbatuar logjikën kryesore të lojës.

Këtu është zbatimi përfundimtar i 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)
    }
}

Tani le të flasim pak për protokollet e rëndësishme.

Protokollet

Puna me protokolle është thelbi i programimit Swift. Protokollet ofrojnë aftësinë për të përcaktuar rregullat për një klasë, strukturë ose numërim. Ky parim ju lejon të shkruani kod modular dhe të zgjerueshëm. Në fakt, ky është një model që ne po e zbatojmë tashmë për collectionView në GameController. Tani le të bëjmë versionin tonë. Sintaksa do të duket si kjo:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Ne e dimë se një protokoll na lejon të përcaktojmë rregulla ose udhëzime për zbatimin e një klase, kështu që le të mendojmë se cilat duhet të jenë ato. Ju duhen katër në total.

  • Fillimi i lojës: memorieGameDidStart.
  • Duhet ta ktheni kartën me fytyrë poshtë: memoryGameShowCards.
  • Duhet ta ktheni kartën me fytyrë poshtë: memoryGameHideCards.
  • Fundi i lojës: memorieGameDidEnd.

Të katër metodat mund të zbatohen për klasën kryesore, e cila është GameController.

memoriaGameDidStart

Kur ekzekutohet kjo metodë, loja duhet të fillojë (përdoruesi shtyp PLAY). Këtu thjesht do të rifreskojmë përmbajtjen duke thirrur collectionView.reloadData(), e cila do të përziejë kartat.

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

MemorieGameShow Cards

Ne e quajmë këtë metodë nga collectionSDViewSelectItemAt. Së pari tregon kartën e zgjedhur. Më pas kontrollon për të parë nëse ka një kartë të pakrahasueshme në grupin e kartave të shfaqura (nëse numri i kartave të shfaqura është tek). Nëse ka një të tillë, karta e zgjedhur krahasohet me të. Nëse fotografitë janë të njëjta, të dyja kartat shtohen te kartat e shfaqura dhe mbeten të kthyera lart. Nëse është ndryshe, karta i lë kartat të shfaqura dhe të dyja janë kthyer me fytyrë poshtë.

memorieGameHideCards

Nëse kartat nuk përputhen, thirret kjo metodë dhe imazhet e kartës fshihen.

i treguar = i rremë.

memorieGameDidEnd

Kur thirret kjo metodë, do të thotë që të gjitha letrat janë zbuluar tashmë dhe janë në listën e kartave të shfaqura: kartat e shfaqura. numërimi = kartat. numërimi, kështu që loja ka përfunduar. Metoda thirret në mënyrë specifike pasi kemi thirrur endGame() për të vendosur isPlaying var në false, pas së cilës shfaqet mesazhi i përfundimit të lojës. Gjithashtu alertController përdoret si tregues për kontrolluesin. thirret viewDidDisappear dhe loja rivendoset.

Ja se si duket e gjitha në 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()
    }
}

Shkrimi i një loje me karta memorie në Swift
Në fakt, kjo është e gjitha. Ju mund ta përdorni këtë projekt për të krijuar versionin tuaj të lojës.

Gëzuar kodimin!

Skillbox rekomandon:

Burimi: www.habr.com

Shto një koment