Mälukaartide mängu kirjutamine Swiftis

Mälukaartide mängu kirjutamine Swiftis

Selles artiklis kirjeldatakse lihtsa mälutreeningu mängu loomise protsessi, mis mulle väga meeldib. Lisaks sellele, et see on iseenesest hea, õpite ka Swifti klasside ja protokollide kohta natuke rohkem. Aga enne kui alustame, mõistame mängu ennast.

Tuletame meelde: kõigile "Habr" lugejatele - allahindlus 10 000 rubla, kui registreerute mis tahes Skillboxi kursusele, kasutades sooduskoodi "Habr".

Skillbox soovitab: Hariv veebikursus "Java arendaja elukutse".

Kuidas mängida mälukaarti

Mäng algab kaartide komplekti demonstreerimisega. Nad lamavad näoga allapoole (vastavalt, pilt alla). Kui klõpsate ühel, avaneb pilt mõneks sekundiks.

Mängija ülesanne on leida kõik samade piltidega kaardid. Kui pärast esimese kaardi avamist keerad teise ümber ja pildid ühtivad, jäävad mõlemad kaardid avatuks. Kui need ei ühti, suletakse kaardid uuesti. Eesmärk on kõik avada.

Projekti struktuur

Selle mängu lihtsa versiooni loomiseks vajate järgmisi komponente:

  • Üks kontroller: GameController.swift.
  • Üks vaade: CardCell.swift.
  • Kaks mudelit: MemoryGame.swift ja Card.swift.
  • Main.soryboard, et tagada kogu komponentide komplekti kättesaadavus.

Alustame mängu kõige lihtsamast komponendist ehk kaartidest.

Card.swift

Kaardimudelil on kolm atribuuti: id igaühe identifitseerimiseks, tõeväärtus muutuja, mis näitab kaardi olekut (peidetud või avatud) ja artworkURL kaartidel olevate piltide jaoks.

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

Samuti on teil vaja järgmisi meetodeid, et juhtida kasutaja interaktsiooni kaartidega.

Meetod pildi kuvamiseks kaardil. Siin lähtestame kõik omadused vaikeseadetele. ID jaoks genereerime juhusliku ID, kutsudes välja NSUUIS().uuidString.

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

ID-kaartide võrdlemise meetod.

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

Igast kaardist koopia loomise meetod - selleks, et saada rohkem ühesuguseid. See meetod tagastab sarnaste väärtustega kaardi.

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

Ja kaartide segamiseks alguses on vaja veel ühte meetodit. Teeme sellest massiivi klassi laienduse.

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

Ja siin on kaardi mudeli koodi rakendamine koos kõigi omaduste ja meetoditega.

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

Lase käia.

Teine mudel on MemoryGame, siin seame 4*4 ruudustiku. Mudelil on sellised omadused nagu kaardid (kaartide massiiv ruudustikus), kaartide massiiv kuvatud juba avatud kaartidega ja tõeväärtus muutuja isPlaying, et jälgida mängu olekut.

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

Samuti peame välja töötama meetodid kasutajate suhtluse kontrollimiseks võrguga.

Meetod, mis segab kaarte ruudustikus.

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

Uue mängu loomise meetod. Siin nimetame esimest meetodit esialgse paigutuse alustamiseks ja isPlaying muutuja lähtestamiseks tõeseks.

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

Kui tahame mängu uuesti käivitada, siis seame isPlaying muutuja väärtuseks false ja eemaldame kaartide esialgse paigutuse.

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

Klikitud kaartide kontrollimise meetod. Temast lähemalt hiljem.

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

Meetod, mis tagastab konkreetse kaardi asukoha.

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

Valitud kaardi standardile vastavuse kontrollimine.

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

See meetod loeb massiivi **cardsShown** viimast elementi ja tagastab mittevastava kaardi.

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

Main.soryboard näeb välja umbes selline:

Mälukaartide mängu kirjutamine Swiftis

Esialgu peate uue mängu seadistama kontrolleris vaateks viewDidLoad, kaasa arvatud ruudustiku pildid. Mängus esindab seda kõike 4*4 kollektsioonView. Kui te pole kollektsiooniga View veel tuttav, siis siin see on saate vajaliku teabe.

Seadistame GameControlleri rakenduse juurkontrolleriks. GameControlleril on kollektsioonView, mida me nimetame IBO-outletiks. Veel üks viide on IBAction onStartGame() nupule, see on UIBupp, näete seda süžeeskeemis nimega PLAY.

Natuke kontrollerite rakendamisest:

  • Esiteks initsialiseerime kaks peamist objekti – ruudustiku: mäng = MemoryGame() ja kaartide komplekti: kaardid = [Card]().
  • Algmuutujateks määrasime viewDidLoad, see on esimene meetod, mida mängu käitamise ajal kutsutakse.
  • collectionView on peidetud, kuna kõik kaardid on peidetud, kuni kasutaja vajutab nuppu PLAY.
  • Niipea, kui vajutame PLAY, käivitub jaotis onStartGame IBAction ja me määrame atribuudi collectionView isHidden väärtuseks false, et kaardid saaksid nähtavaks muutuda.
  • Iga kord, kui kasutaja kaardi valib, kutsutakse välja meetod didSelectItemAt. Meetodis kutsume mängu põhiloogika rakendamiseks didSelectCardi.

Siin on GameControlleri viimane rakendus:

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

Räägime nüüd natuke olulistest protokollidest.

Protokollid

Protokollidega töötamine on Swifti programmeerimise tuum. Protokollid võimaldavad määratleda klassi, struktuuri või loendi reegleid. See põhimõte võimaldab kirjutada modulaarset ja laiendatavat koodi. Tegelikult on see muster, mida me GameControlleris juba CollectionView jaoks rakendame. Nüüd teeme oma versiooni. Süntaks näeb välja selline:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Teame, et protokoll võimaldab meil määratleda reegleid või juhiseid klassi rakendamiseks, seega mõelgem, millised need olema peaksid. Kokku vajate nelja.

  • Mängu algus: memoryGameDidStart.
  • Peate pöörama kaardi esiküljega allapoole: memoryGameShowCards.
  • Peate kaardi pöörama esiküljega allapoole: memoryGameHideCards.
  • Mängu lõpp: memoryGameDidEnd.

Kõiki nelja meetodit saab rakendada põhiklassi jaoks, milleks on GameController.

memoryGameDidStart

Selle meetodi käivitamisel peaks mäng algama (kasutaja vajutab PLAY). Siin laadime sisu lihtsalt uuesti, kutsudes esile collectionView.reloadData(), mis segab kaarte.

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

mäluGameShowCards

Nimetame seda meetodit kollektsioonistSDViewSelectItemAt. Esmalt näitab see valitud kaarti. Seejärel kontrollib, kas massiivis cardsShown on sobimatu kaart (kui kuvatavate kaartide arv on paaritu). Kui see on olemas, võrreldakse valitud kaarti sellega. Kui pildid on samad, lisatakse mõlemad kaardid kuvatud kaartidele ja jäävad pildiga ülespoole. Kui kaart on erinev, jätab kaart kuvatud kaardid ja mõlemad pööratakse esiküljega allapoole.

mäluGameHideCards

Kui kaardid ei ühti, kutsutakse see meetod välja ja kaardipildid peidetakse.

näidatud = vale.

mäluGameDidEnd

Kui seda meetodit kutsutakse, tähendab see, et kõik kaardid on juba avalikustatud ja on nimekirjas cardsShown: cardsShown.count = cards.count, seega on mäng läbi. Meetodit kutsutakse spetsiaalselt pärast seda, kui oleme kutsunud endGame(), et määrata isPlaying var väärtuseks false, mille järel kuvatakse mängu lõpu teade. Samuti kasutatakse kontrolleri indikaatorina alertControlleri. Kutsutakse välja viewDidDisappear ja mäng lähtestatakse.

Siin näeb see välja GameControlleris:

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

Mälukaartide mängu kirjutamine Swiftis
Tegelikult on see kõik. Selle projekti abil saate luua oma mängu versiooni.

Head kodeerimist!

Skillbox soovitab:

Allikas: www.habr.com

Lisa kommentaar