Свифтте жад картасы ойынын жазу

Свифтте жад картасы ойынын жазу

Бұл мақалада маған өте ұнайтын қарапайым есте сақтау ойынын жасау процесі сипатталған. Өздігінен жақсы болумен қатар, сіз Swift сабақтары мен хаттамалары туралы көбірек біле аласыз. Бірақ бастамас бұрын, ойынның өзін түсінейік.

Біз еске саламыз: «Хабрдың» барлық оқырмандары үшін - «Habr» жарнамалық кодын пайдаланып кез келген Skillbox курсына жазылу кезінде 10 000 рубль көлемінде жеңілдік.

Skillbox ұсынады: Білім беру онлайн курсы «Мамандығы Java әзірлеушісі».

Жад картасын қалай ойнауға болады

Ойын карталар жинағын көрсетуден басталады. Олар бетін төмен қаратып жатады (тиісінше, сурет төмен). Кез келгенін басқан кезде сурет бірнеше секундқа ашылады.

Ойыншының міндеті - бірдей суреттері бар барлық карталарды табу. Егер бірінші картаны ашқаннан кейін екіншісін аударып, суреттер сәйкес келсе, екі карта да ашық қалады. Егер олар сәйкес келмесе, карталар қайтадан жабылады. Мақсат - бәрін ашу.

Жоба құрылымы

Осы ойынның қарапайым нұсқасын жасау үшін сізге келесі компоненттер қажет:

  • Бір контроллер: GameController.swift.
  • Бір көрініс: CardCell.swift.
  • Екі үлгі: MemoryGame.swift және Card.swift.
  • Құрамдастардың барлық жиынтығы қолжетімді болуын қамтамасыз ету үшін Main.storyboard.

Біз ойынның қарапайым құрамдас бөлігінен, яғни карталардан бастаймыз.

Card.swift

Карта үлгісінің үш қасиеті болады: әрқайсысын анықтау үшін идентификатор, картаның күйін көрсету үшін көрсетілген логикалық айнымалы (жасырын немесе ашық) және карталардағы кескіндер үшін artworkURL.

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

Сондай-ақ пайдаланушының карталармен әрекеттесуін басқару үшін сізге мына әдістер қажет:

Карточкадағы суретті көрсету әдісі. Мұнда біз барлық сипаттарды әдепкіге қайтарамыз. Идентификатор үшін NSUUIS().uuidString шақыру арқылы кездейсоқ идентификатор жасаймыз.

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)    
}
 
init(card: Card) {        
    self.id = card.id        
    self.shown = card.shown        
    self.artworkURL = card.artworkURL    
}

Бастапқыда карталарды араластыру үшін тағы бір әдіс қажет. Біз оны Array класының кеңейтімін жасаймыз.

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

Міне, барлық қасиеттері мен әдістері бар Card моделіне арналған кодты іске асыру.

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

Біз одан әрі қарай жүреміз.

Екінші модель - MemoryGame, мұнда біз 4*4 торды орнаттық. Модельде карталар (тордағы карталар массиві), ашық карталары бар cardsShown массиві және ойын күйін бақылау үшін isPlaying логикалық айнымалысы сияқты қасиеттер болады.

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

Сондай-ақ пайдаланушының тормен әрекеттесуін бақылау әдістерін әзірлеуіміз керек.

Тордағы карталарды араластыратын әдіс.

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

Жаңа ойын құру әдісі. Мұнда біз бастапқы орналасуды бастау және isPlaying айнымалысын шын мәніне инициализациялаудың бірінші әдісін шақырамыз.

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

Ойынды қайта бастағымыз келсе, содан кейін isPlaying айнымалы мәнін false мәніне орнатып, карталардың бастапқы орналасуын алып тастаймыз.

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

Басылған карталарды тексеру әдісі. Ол туралы кейінірек.

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

Белгілі бір картаның орнын қайтаратын әдіс.

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

Таңдалған картаның стандартқа сәйкестігін тексеру.

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

Бұл әдіс **cardsShown** массивіндегі соңғы элементті оқиды және сәйкес келмейтін картаны қайтарады.

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 және GameController.swift

Main.storyboard келесідей көрінеді:

Свифтте жад картасы ойынын жазу

Бастапқыда жаңа ойынды контроллерде viewDidLoad ретінде орнату керек, соның ішінде торға арналған кескіндер. Ойында мұның барлығы 4*4 collectionView арқылы көрсетіледі. CollectionView қолданбасымен әлі таныс болмасаңыз, міне қажетті ақпаратты ала аласыз.

Біз GameController қолданбасын түбірлік контроллер ретінде конфигурациялаймыз. GameController жиынтығында IBOutlet ретінде сілтеме жасайтын коллекция көрінісі болады. Тағы бір сілтеме IBAction onStartGame() түймесі, бұл UIButton, оны PLAY деп аталатын сюжеттер тақтасында көруге болады.

Контроллерлерді енгізу туралы аздап:

  • Біріншіден, біз екі негізгі нысанды – торды инициализациялаймыз: ойын = MemoryGame() және карталар жинағы: карталар = [Карта]().
  • Біз бастапқы айнымалыларды viewDidLoad ретінде орнаттық, бұл ойын іске қосылған кезде шақырылатын бірінші әдіс.
  • collectionView жасырын күйге орнатылған, себебі пайдаланушы PLAY түймесін басқанша барлық карталар жасырылады.
  • PLAY пернесін басқаннан кейін onStartGame IBAction бөлімі басталады және біз карталар көрінуі үшін collectionView isHidden сипатын жалған мәніне орнатамыз.
  • Пайдаланушы картаны таңдаған сайын didSelectItemAt әдісі шақырылады. Әдісте біз негізгі ойын логикасын жүзеге асыру үшін didSelectCard деп атаймыз.

Міне, соңғы 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)
    }
}

Енді маңызды хаттамалар туралы аздап сөйлесейік.

Протоколдар

Протоколдармен жұмыс істеу - Swift бағдарламалауының өзегі. Протоколдар сыныпқа, құрылымға немесе тізімге арналған ережелерді анықтау мүмкіндігін береді. Бұл принцип модульдік және кеңейтілетін кодты жазуға мүмкіндік береді. Шын мәнінде, бұл GameController жүйесінде collectionView үшін біз қазірдің өзінде енгізіп жатқан үлгі. Енді өз нұсқамызды жасайық. Синтаксис келесідей болады:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Біз протоколдың классты енгізу ережелерін немесе нұсқауларын анықтауға мүмкіндік беретінін білеміз, сондықтан олардың қандай болуы керектігі туралы ойланайық. Барлығы төртеуі керек.

  • Ойынның басталуы: memoryGameDidStart.
  • Картаны төмен қаратып қою керек: memoryGameShowCards.
  • Картаны төмен қаратып қою керек: memoryGameHideCards.
  • Ойынның соңы: memoryGameDidEnd.

Барлық төрт әдісті GameController болып табылатын негізгі класс үшін жүзеге асыруға болады.

memoryGameDidStart

Бұл әдіс іске қосылғанда ойын басталуы керек (пайдаланушы PLAY түймесін басады). Мұнда біз карталарды араластыратын collectionView.reloadData() шақыру арқылы жай ғана мазмұнды қайта жүктейміз.

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

жад ойынын көрсету карталары

Біз бұл әдісті collectionSDViewSelectItemAt деп атаймыз. Алдымен ол таңдалған картаны көрсетеді. Содан кейін cardsShown массивінде сәйкес келмейтін карта бар-жоғын тексереді (егер Көрсетілген карталардың саны тақ болса). Егер бар болса, таңдалған карта онымен салыстырылады. Суреттер бірдей болса, екі карта да көрсетілген карталарға қосылады және беті жоғары күйінде қалады. Егер басқаша болса, карта карталарды көрсетеді және екеуі де бетін төмен қаратады.

жад ойынын жасыру карталары

Егер карталар сәйкес келмесе, бұл әдіс шақырылады және карта кескіндері жасырылады.

көрсетілген = жалған.

memoryGameDidEnd

Бұл әдіс шақырылғанда, бұл барлық карталардың ашылғанын және cardsShown тізімінде екенін білдіреді: cardsShown.count = cards.count, сондықтан ойын аяқталды. Әдіс isPlaying var мәнін "false" мәніне орнату үшін endGame() қызметін шақырғаннан кейін арнайы шақырылады, содан кейін ойынның аяқталу хабары көрсетіледі. Сондай-ақ alertController контроллер үшін көрсеткіш ретінде пайдаланылады. viewDidDisappear шақырылады және ойын қалпына келтіріледі.

Міне, бәрі 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()
    }
}

Свифтте жад картасы ойынын жазу
Шындығында, бәрі осы. Сіз бұл жобаны ойынның жеке нұсқасын жасау үшін пайдалана аласыз.

Бақытты кодтау!

Skillbox ұсынады:

Ақпарат көзі: www.habr.com

пікір қалдыру