Að skrifa minniskortaleik í Swift

Að skrifa minniskortaleik í Swift

Þessi grein lýsir ferlinu við að búa til einfaldan minnisþjálfunarleik sem ég hef mjög gaman af. Fyrir utan að vera góður í sjálfu sér muntu læra aðeins meira um Swift námskeið og samskiptareglur eftir því sem þú ferð. En áður en við byrjum skulum við skilja leikinn sjálfan.

Við minnum á: fyrir alla Habr lesendur - 10 rúblur afsláttur þegar þú skráir þig á hvaða Skillbox námskeið sem er með því að nota Habr kynningarkóðann.

Skillbox mælir með: Fræðslunámskeið á netinu "Profession Java verktaki".

Hvernig á að spila Memory Card

Leikurinn hefst með því að sýna sett af spilum. Þeir liggja með andlitið niður (í sömu röð, mynd niður). Þegar þú smellir á einhvern opnast myndin í nokkrar sekúndur.

Verkefni leikmannsins er að finna öll spilin með sömu myndunum. Ef þú snýr því öðru við eftir að fyrsta spilið hefur verið opnað og myndirnar passa saman, eru bæði spilin opin. Ef þau passa ekki saman er spilunum lokað aftur. Markmiðið er að opna allt.

Uppbygging verkefnis

Til að búa til einfalda útgáfu af þessum leik þarftu eftirfarandi hluti:

  • Einn stjórnandi: GameController.swift.
  • One View: CardCell.swift.
  • Tvær gerðir: MemoryGame.swift og Card.swift.
  • Main.storyboard til að tryggja að allt sett af íhlutum sé tiltækt.

Við byrjum á einfaldasta þætti leiksins, spilunum.

Card.swift

Kortalíkanið mun hafa þrjá eiginleika: auðkenni til að bera kennsl á hvern og einn, boolean breyta sem sýnd er til að tilgreina stöðu kortsins (falið eða opið) og artworkURL fyrir myndirnar á kortunum.

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

Þú þarft einnig þessar aðferðir til að stjórna notendasamskiptum við kort:

Aðferð til að birta mynd á korti. Hér endurstillum við allar eignir í sjálfgefið. Fyrir auðkenni búum við til handahófskennt auðkenni með því að kalla NSUUIS().uuidString.

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

Aðferð til að bera saman skilríki.

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

Aðferð til að búa til afrit af hverju korti - til að fá fleiri eins. Þessi aðferð mun skila korti með svipuðum gildum.

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

Og eina aðferð í viðbót þarf til að stokka spilin í byrjun. Við munum gera það að framlengingu á Array bekknum.

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

Og hér er útfærsla kóðans fyrir Card líkanið með öllum eiginleikum og aðferðum.

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

Fara á undan.

Annað gerðin er MemoryGame, hér setjum við 4*4 rist. Líkanið mun hafa eiginleika eins og spil (fylki af spilum á rist), spil sem sýnt er með spilum sem eru þegar opin og boolean breytu er að spila til að fylgjast með stöðu leiksins.

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

Við þurfum líka að þróa aðferðir til að stjórna samskiptum notenda við netið.

Aðferð sem stokkar spil í rist.

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

Aðferð til að búa til nýjan leik. Hér köllum við fyrstu aðferðina til að hefja upphafsútlitið og frumstilla isPlaying breytuna á satt.

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

Ef við viljum endurræsa leikinn, þá setjum við isPlaying breytuna á false og fjarlægjum upphafsuppsetningu kortanna.

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

Aðferð til að sannreyna smellt kort. Meira um hann síðar.

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

Aðferð sem skilar stöðu tiltekins korts.

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

Athugaðu hvort valið kort sé í samræmi við staðalinn.

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

Þessi aðferð les síðasta þáttinn í **cardsShown** fylkinu og skilar kortinu sem ekki samsvarar.

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

Main.storyboard lítur eitthvað svona út:

Að skrifa minniskortaleik í Swift

Upphaflega þarftu að stilla nýja leikinn sem viewDidLoad í stjórnandanum, þar á meðal myndirnar fyrir ristina. Í leiknum verður allt þetta táknað með 4*4 collectionView. Ef þú ert ekki enn kunnugur collectionView, þá er það hér þú getur fengið þær upplýsingar sem þú þarft.

Við munum stilla GameController sem rótarstýringu forritsins. GameController mun hafa collectionView sem við munum vísa til sem IBOutlet. Önnur tilvísun er í IBAction onStartGame() hnappinn, þetta er UIButton, þú getur séð það á söguborðinu sem heitir PLAY.

Smá um innleiðingu stýrimanna:

  • Í fyrsta lagi frumstillum við tvo aðalhluti - ristina: leikur = MemoryGame(), og sett af spilum: spil = [Card]().
  • Við stillum upphafsbreyturnar sem viewDidLoad, þetta er fyrsta aðferðin sem er kölluð á meðan leikurinn er í gangi.
  • collectionView er stillt á falið vegna þess að öll spil eru falin þar til notandinn ýtir á PLAY.
  • Um leið og við ýtum á PLAY byrjar onStartGame IBAction hlutinn og við setjum eiginleikann collectionView isHidden á false svo að spilin geti orðið sýnileg.
  • Í hvert sinn sem notandi velur kort er didSelectItemAt aðferðin kölluð. Í aðferðinni sem við köllum didSelectCard til að innleiða rökfræði aðalleiksins.

Hér er lokaútfærsla 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)
    }
}

Nú skulum við tala aðeins um mikilvægar samskiptareglur.

Bókanir

Vinna með samskiptareglur er kjarninn í Swift forritun. Samskiptareglur veita möguleika á að skilgreina reglur fyrir flokk, uppbyggingu eða upptalningu. Þessi meginregla gerir þér kleift að skrifa mát og teygjanlegan kóða. Reyndar er þetta mynstur sem við erum nú þegar að innleiða fyrir collectionView í GameController. Nú skulum við búa til okkar eigin útgáfu. Setningafræðin mun líta svona út:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Við vitum að siðareglur gera okkur kleift að skilgreina reglur eða leiðbeiningar um útfærslu bekkjar, svo við skulum hugsa um hvað þær ættu að vera. Þú þarft fjóra samtals.

  • Byrjun leiks: memoryGameDidStart.
  • Þú þarft að snúa kortinu niður: memoryGameShowCards.
  • Þú þarft að snúa kortinu niður: memoryGameHideCards.
  • Leikslok: memoryGameDidEnd.

Hægt er að útfæra allar fjórar aðferðirnar fyrir aðalflokkinn, sem er GameController.

memoryGameDidStart

Þegar þessi aðferð er keyrð ætti leikurinn að byrja (notandinn ýtir á PLAY). Hér munum við einfaldlega endurhlaða efnið með því að hringja í collectionView.reloadData(), sem mun stokka spilin.

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

memoryGameShowCards

Við köllum þessa aðferð frá collectionSDViewSelectItemAt. Fyrst sýnir það valið kort. Athugar síðan hvort það sé ósamþykkt spil í spilunum sem sýnd eru (ef fjöldi spilanna sem sýnd er er ójafn). Ef það er eitt, er valið kort borið saman við það. Ef myndirnar eru þær sömu er báðum spilunum bætt við spilin sem sýnd eru og eru áfram með andlitið upp. Ef annað skilur spilin eftir sem sýnd eru og báðum er snúið niður.

memoryGameHideCards

Ef spilin passa ekki saman er þessi aðferð kölluð og kortamyndirnar eru faldar.

sýnt = rangt.

memoryGameDidEnd

Þegar þessi aðferð er kölluð þýðir það að öll spil eru þegar opinberuð og eru í spilunum Sýnd listanum: cardsShown.count = cards.count, þannig að leiknum er lokið. Aðferðin er kölluð sérstaklega eftir að við höfum kallað endGame() til að stilla isPlaying var á false, eftir það birtast skilaboðin um leiklok. Einnig er alertController notað sem vísir fyrir stjórnandann. kallað er á viewDidDisappear og leikurinn er endurstilltur.

Svona lítur þetta allt út í 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()
    }
}

Að skrifa minniskortaleik í Swift
Reyndar, það er allt. Þú getur notað þetta verkefni til að búa til þína eigin útgáfu af leiknum.

Til hamingju með kóðun!

Skillbox mælir með:

Heimild: www.habr.com

Bæta við athugasemd