Ysgrifennu Gêm Cardiau Cof yn Swift

Ysgrifennu Gêm Cardiau Cof yn Swift

Mae'r erthygl hon yn disgrifio'r broses o greu gêm hyfforddi cof syml yr wyf yn ei hoffi'n fawr. Ar wahân i fod yn dda ynddo'i hun, byddwch chi'n dysgu ychydig mwy am ddosbarthiadau a phrotocolau Swift wrth i chi fynd. Ond cyn i ni ddechrau, gadewch i ni ddeall y gêm ei hun.

Rydym yn atgoffa: i holl ddarllenwyr "Habr" - gostyngiad o 10 rubles wrth gofrestru ar unrhyw gwrs Skillbox gan ddefnyddio'r cod hyrwyddo "Habr".

Mae Skillsbox yn argymell: Cwrs addysgol ar-lein "Datblygwr Java Proffesiynol".

Sut i chwarae Cerdyn Cof

Mae'r gêm yn dechrau gydag arddangosiad o set o gardiau. Maent yn gorwedd wyneb i lawr (yn y drefn honno, delwedd i lawr). Pan gliciwch ar unrhyw un, mae'r ddelwedd yn agor am ychydig eiliadau.

Tasg y chwaraewr yw dod o hyd i bob cerdyn gyda'r un lluniau. Os, ar ôl agor y cerdyn cyntaf, rydych chi'n troi'r ail drosodd a bod y lluniau'n cyd-fynd, mae'r ddau gerdyn yn aros ar agor. Os nad ydynt yn cyfateb, mae'r cardiau ar gau eto. Y nod yw agor popeth.

Strwythur y prosiect

I greu fersiwn syml o'r gêm hon mae angen y cydrannau canlynol arnoch:

  • Un Rheolydd: GameController.swift.
  • Un Golwg: CardCell.swift.
  • Dau Fodel: MemoryGame.swift a Card.swift.
  • Main.storyboard i sicrhau bod y set gyfan o gydrannau ar gael.

Rydym yn dechrau gyda'r elfen symlaf o'r gêm, y cardiau.

Card.swift

Bydd gan fodel y cerdyn dri phriodweddau: id i adnabod pob un, newidyn boolean a ddangosir i nodi statws y cerdyn (cudd neu agored), a artworkURL ar gyfer y delweddau ar y cardiau.

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

Bydd angen y dulliau hyn arnoch hefyd i reoli rhyngweithio defnyddwyr â mapiau:

Dull o arddangos delwedd ar gerdyn. Yma rydym yn ailosod pob eiddo i ddiofyn. Ar gyfer id, rydym yn cynhyrchu ID ar hap trwy ffonio NSUIS().uuidString.

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

Dull o gymharu cardiau adnabod.

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

Dull o greu copi o bob cerdyn - er mwyn cael nifer fwy o rai union yr un fath. Bydd y dull hwn yn dychwelyd cerdyn gyda gwerthoedd tebyg.

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

Ac mae angen un dull arall i gymysgu'r cardiau ar y dechrau. Byddwn yn ei wneud yn estyniad o'r dosbarth Array.

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

A dyma weithrediad y cod ar gyfer model y Cerdyn gyda'r holl briodweddau a dulliau.

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

Ewch ymlaen.

Yr ail fodel yw MemoryGame, dyma ni'n gosod grid 4 * 4. Bydd gan y model briodweddau megis cardiau (amrywiaeth o gardiau ar grid), cyfres o gardiau Dangosir gyda chardiau eisoes ar agor, a newidyn boolean isPlaying i olrhain statws y gêm.

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

Mae angen i ni hefyd ddatblygu dulliau i reoli rhyngweithio defnyddwyr â'r grid.

Dull sy'n cymysgu cardiau mewn grid.

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

Dull o greu gêm newydd. Yma rydyn ni'n galw'r dull cyntaf i gychwyn y cynllun cychwynnol a chychwyn y newidyn isPlaying i wir.

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

Os ydym am ailgychwyn y gêm, yna rydym yn gosod y newidyn isPlaying i ffug a dileu cynllun cychwynnol y cardiau.

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

Dull ar gyfer gwirio cardiau wedi'u clicio. Mwy amdano yn nes ymlaen.

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

Dull sy'n dychwelyd lleoliad cerdyn penodol.

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

Gwirio cydymffurfiad y cerdyn a ddewiswyd â'r safon.

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

Mae'r dull hwn yn darllen yr elfen olaf yn yr arae **cardsShown** ac yn dychwelyd y cerdyn nad yw'n cyfateb.

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

Prif.bwrdd stori a GameController.swift

Mae prif fwrdd stori yn edrych rhywbeth fel hyn:

Ysgrifennu Gêm Cardiau Cof yn Swift

I ddechrau, mae angen i chi osod y gêm newydd fel viewDidLoad yn y rheolydd, gan gynnwys y delweddau ar gyfer y grid. Yn y gêm, bydd hyn i gyd yn cael ei gynrychioli gan gasgliad 4 * 4View. Os nad ydych chi'n gyfarwydd â collectionView eto, dyma fe gallwch gael y wybodaeth sydd ei hangen arnoch.

Byddwn yn ffurfweddu'r GameController fel rheolydd gwraidd y rhaglen. Bydd gan y GameController View Casgliad y byddwn yn cyfeirio ato fel IBOoutlet. Mae cyfeiriad arall at y botwm IBAction onStartGame(), UIButton yw hwn, gallwch ei weld yn y bwrdd stori o'r enw CHWARAE.

Ychydig am weithrediad rheolwyr:

  • Yn gyntaf, rydym yn cychwyn dau brif wrthrych - y grid: gêm = MemoryGame(), a set o gardiau: cardiau = [Cerdyn]().
  • Rydym yn gosod y newidynnau cychwynnol fel viewDidLoad, dyma'r dull cyntaf a elwir tra bod y gêm yn rhedeg.
  • Mae collectionView wedi'i osod i gudd oherwydd bod pob cerdyn wedi'i guddio nes bod y defnyddiwr yn pwyso CHWARAE.
  • Cyn gynted ag y byddwn yn pwyso CHWARAE, mae'r adran IBAction onStartGame yn dechrau, ac rydym yn gosod y casgliadView isHidden eiddo i ffug fel y gall y cardiau ddod yn weladwy.
  • Bob tro mae'r defnyddiwr yn dewis cerdyn, gelwir y dull didSelectItemAt. Yn y dull rydym yn galw didSelectCard i weithredu'r prif resymeg gêm.

Dyma weithrediad terfynol 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)
    }
}

Nawr, gadewch i ni siarad ychydig am y protocolau pwysig.

Protocolau

Gweithio gyda phrotocolau yw craidd rhaglennu Swift. Mae protocolau yn darparu'r gallu i ddiffinio rheolau ar gyfer dosbarth, strwythur neu rif. Mae'r egwyddor hon yn caniatáu ichi ysgrifennu cod modiwlaidd ac estynadwy. Mewn gwirionedd, mae hwn yn batrwm yr ydym eisoes yn ei weithredu ar gyfer collectionView yn GameController. Nawr, gadewch i ni wneud ein fersiwn ein hunain. Bydd y gystrawen yn edrych fel hyn:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Gwyddom fod protocol yn ein galluogi i ddiffinio rheolau neu gyfarwyddiadau ar gyfer gweithredu dosbarth, felly gadewch i ni feddwl am yr hyn y dylent fod. Mae angen pedwar i gyd.

  • Dechrau gêm: memoryGameDidStart.
  • Mae angen i chi droi'r cerdyn wyneb i lawr: memoryGameShowCards.
  • Mae angen i chi droi'r cerdyn wyneb i lawr: memoryGameHideCards.
  • Diwedd gêm: memoryGameDidEnd.

Gellir gweithredu'r pedwar dull ar gyfer y prif ddosbarth, sef GameController.

cofGameDidStart

Pan fydd y dull hwn yn cael ei redeg, dylai'r gêm ddechrau (mae'r defnyddiwr yn pwyso CHWARAE). Yma byddwn yn ail-lwytho'r cynnwys trwy ffonio collectionView.reloadData(), a fydd yn cymysgu'r cardiau.

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

memoryGameShowCards

Rydym yn galw'r dull hwn o gasgliadSDViewSelectItemAt. Yn gyntaf mae'n dangos y cerdyn a ddewiswyd. Yna gwirio i weld a oes cerdyn heb ei gyfateb yn yr arae cardiauShown (os yw nifer y cardiauShown yn odrif). Os oes un, mae'r cerdyn a ddewiswyd yn cael ei gymharu ag ef. Os yw'r lluniau yr un peth, mae'r ddau gerdyn yn cael eu hychwanegu at cardsShown ac yn aros wyneb i fyny. Os yw'n wahanol, mae'r cerdyn yn gadael cardsShown ac mae'r ddau yn cael eu troi wyneb i waered.

memoryGameHideCards

Os nad yw'r cardiau'n cyfateb, gelwir y dull hwn ac mae'r delweddau cerdyn wedi'u cuddio.

dangosir = ffug.

cofGameDidEnd

Pan elwir y dull hwn, mae'n golygu bod yr holl gardiau eisoes wedi'u datgelu ac maent yn y rhestr cardsShown: cardsShown.count = cards.count, felly mae'r gêm drosodd. Gelwir y dull yn benodol ar ôl i ni alw endGame() i osod yr isPlaying var i ffug, ac ar ôl hynny dangosir neges diwedd y gêm. Hefyd defnyddir alertController fel dangosydd ar gyfer y rheolydd. viewDidDisappear yn cael ei alw ac mae'r gêm yn cael ei ailosod.

Dyma sut mae'r cyfan yn edrych yn 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()
    }
}

Ysgrifennu Gêm Cardiau Cof yn Swift
A dweud y gwir, dyna i gyd. Gallwch ddefnyddio'r prosiect hwn i greu eich fersiwn eich hun o'r gêm.

Codio hapus!

Mae Skillsbox yn argymell:

Ffynhonnell: hab.com

Ychwanegu sylw