Atmiņas karÅ”u spēles rakstÄ«Å”ana programmā Swift

Atmiņas karÅ”u spēles rakstÄ«Å”ana programmā Swift

Å ajā rakstā ir aprakstÄ«ts vienkārÅ”as atmiņas treniņu spēles izveides process, kas man ļoti patÄ«k. Papildus tam, ka tas pats par sevi ir labs, jÅ«s uzzināsit nedaudz vairāk par Swift nodarbÄ«bām un protokoliem. Bet pirms sākam, sapratÄ«sim paÅ”u spēli.

Atgādinām: visiem "Habr" lasītājiem - atlaide 10 000 rubļu, reģistrējoties jebkurā Skillbox kursā, izmantojot "Habr" reklāmas kodu.

Skillbox iesaka: IzglītojoŔs tieŔsaistes kurss "Java izstrādātāja profesija".

Kā spēlēt atmiņas karti

Spēle sākas ar kārÅ”u komplekta demonstrāciju. Viņi guļ ar seju uz leju (attiecÄ«gi, attēls uz leju). NoklikŔķinot uz jebkura, attēls tiek atvērts uz dažām sekundēm.

Spēlētāja uzdevums ir atrast visas kārtis ar vienādiem attēliem. Ja pēc pirmās kartÄ«tes atvērÅ”anas apgriežat otro un attēli sakrÄ«t, abas kartÄ«tes paliek atvērtas. Ja tās nesakrÄ«t, kartes atkal tiek aizvērtas. MērÄ·is ir visu atvērt.

Projekta struktūra

Lai izveidotu vienkārÅ”u Ŕīs spēles versiju, jums ir nepiecieÅ”ami Ŕādi komponenti:

  • Viens kontrolieris: GameController.swift.
  • Viens skats: CardCell.swift.
  • Divi modeļi: MemoryGame.swift un Card.swift.
  • Main.storyboard, lai nodroÅ”inātu, ka ir pieejams viss komponentu komplekts.

Mēs sākam ar vienkārŔāko spēles sastāvdaļu, kārtÄ«m.

Card.swift

Kartes modelim bÅ«s trÄ«s rekvizÄ«ti: ID, lai identificētu katru, BÅ«la mainÄ«gais, kas tiek rādÄ«ts, lai norādÄ«tu kartes statusu (slēpts vai atvērts), un artworkURL kartÄ«tēs esoÅ”ajiem attēliem.

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

Jums bÅ«s nepiecieÅ”amas arÄ« Ŕīs metodes, lai kontrolētu lietotāja mijiedarbÄ«bu ar kartēm:

Metode attēla parādÄ«Å”anai kartē. Å eit mēs atiestatām visus rekvizÄ«tus uz noklusējuma iestatÄ«jumiem. ID mēs Ä£enerējam nejauÅ”u ID, izsaucot NSUUIS().uuidString.

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

ID karŔu salīdzināŔanas metode.

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

Katras kartes kopijas izveides metode - lai iegūtu lielāku skaitu identisku. Šī metode atgriezīs karti ar līdzīgām vērtībām.

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

Un ir nepiecieÅ”ama vēl viena metode, lai sākumā sajauktu kārtis. Mēs to padarÄ«sim par klases Array paplaÅ”inājumu.

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

Un Å”eit ir Kartes modeļa koda ievieÅ”ana ar visām Ä«paŔībām un metodēm.

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

Iet uz priekŔu.

Otrais modelis ir MemoryGame, Å”eit mēs iestatām 4 * 4 režģi. Modelim bÅ«s tādi rekvizÄ«ti kā kārtis (karÅ”u masÄ«vs uz režģa), kārtis ParādÄ«ts masÄ«vs ar jau atvērtām kartēm un BÅ«la mainÄ«gais isPlaying, lai izsekotu spēles statusu.

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

Mums ir arī jāizstrādā metodes, lai kontrolētu lietotāju mijiedarbību ar tīklu.

Metode, kas sajauc kārtis režģī.

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

Jaunas spēles izveides metode. Šeit mēs saucam pirmo metodi, lai sāktu sākotnējo izkārtojumu un inicializētu mainīgo isPlaying uz true.

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

Ja mēs vēlamies atsākt spēli, tad mēs iestatām mainÄ«go isPlaying uz false un noņemam sākotnējo karÅ”u izkārtojumu.

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

NoklikŔķināto kartÄ«Å”u verifikācijas metode. Vairāk par viņu vēlāk.

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

Metode, kas atgriež noteiktas kartes pozīciju.

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

Izvēlētās kartes atbilstības standarta pārbaude.

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

Å Ä« metode nolasa pēdējo elementu masÄ«vā **cardsShown** un atgriež neatbilstoÅ”o karti.

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

Main.storyboard izskatās apmēram Ŕādi:

Atmiņas karÅ”u spēles rakstÄ«Å”ana programmā Swift

Sākotnēji jums ir jāiestata jaunā spēle kontrollerÄ« kā viewDidLoad, ieskaitot režģa attēlus. Spēlē to visu pārstāvēs 4*4 kolekcijaView. Ja vēl neesat pazÄ«stams ar collectionView, Å”eit tas ir jÅ«s varat iegÅ«t nepiecieÅ”amo informāciju.

Mēs konfigurēsim GameController kā lietojumprogrammas saknes kontrolieri. GameController bÅ«s kolekcijaSkats, ko mēs atsaucēsim kā IBOutlet. Vēl viena atsauce ir uz IBAction onStartGame() pogu, Ŕī ir UIBpoga, to var redzēt scenārijā ar nosaukumu PLAY.

Mazliet par kontrolieru ievieŔanu:

  • Pirmkārt, mēs inicializējam divus galvenos objektus - režģi: spēle = MemoryGame () un karÅ”u kopu: kartes = [Card] ().
  • Sākotnējos mainÄ«gos iestatÄ«jām kā viewDidLoad, Ŕī ir pirmā metode, kas tiek izsaukta spēles darbÄ«bas laikā.
  • collectionView ir iestatÄ«ts kā slēpts, jo visas kartÄ«tes ir paslēptas, lÄ«dz lietotājs nospiež PLAY.
  • TiklÄ«dz mēs nospiežam PLAY, tiek sākta onStartGame IBAction sadaļa, un mēs iestatām rekvizÄ«tu collectionView isHidden uz false, lai kartes varētu kļūt redzamas.
  • Katru reizi, kad lietotājs izvēlas karti, tiek izsaukta metode didSelectItemAt. Metodē mēs izsaucam didSelectCard, lai Ä«stenotu galveno spēles loÄ£iku.

Å eit ir pēdējā GameController ievieÅ”ana:

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

Tagad parunāsim nedaudz par svarīgajiem protokoliem.

Protokoli

Darbs ar protokoliem ir Swift programmÄ“Å”anas pamatā. Protokoli nodroÅ”ina iespēju definēt noteikumus klasei, struktÅ«rai vai uzskaitei. Å is princips ļauj rakstÄ«t modulāru un paplaÅ”ināmu kodu. Faktiski Å”is ir modelis, ko mēs jau ievieÅ”am CollectionView programmā GameController. Tagad izveidosim savu versiju. Sintakse izskatÄ«sies Ŕādi:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

Mēs zinām, ka protokols ļauj mums definēt noteikumus vai instrukcijas klases ievieÅ”anai, tāpēc padomāsim, kādiem tiem vajadzētu bÅ«t. Kopā vajag četrus.

  • Spēles sākums: memoryGameDidStart.
  • Jums jāpagriež karte ar priekÅ”pusi uz leju: memoryGameShowCards.
  • Jums jāpagriež karte ar priekÅ”pusi uz leju: memoryGameHideCards.
  • Spēles beigas: memoryGameDidEnd.

Visas četras metodes var ieviest galvenajai klasei, kas ir GameController.

memoryGameDidStart

Kad Ŕī metode tiek palaista, spēlei jāsākas (lietotājs nospiež PLAY). Å eit mēs vienkārÅ”i pārlādēsim saturu, izsaucot collectionView.reloadData(), kas sajauc kartÄ«tes.

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

memoryGameShowCards

Mēs Å”o metodi saucam no kolekcijasSDViewSelectItemAt. Vispirms tiek parādÄ«ta izvēlētā karte. Pēc tam pārbauda, ā€‹ā€‹vai masÄ«vā cardsShown ir nesaskaņota karte (ja ParādÄ«to kārÅ”u skaits ir nepāra). Ja tāda ir, izvēlētā karte tiek salÄ«dzināta ar to. Ja attēli ir vienādi, abas kārtis tiek pievienotas ParādÄ«tajām kartēm un paliek ar attēlu uz augÅ”u. Ja atŔķiras, kartÄ«te atstāj kārtisParādÄ«tas un abas ir pagrieztas ar attēlu uz leju.

memoryGameHideCards

Ja kartes nesakrÄ«t, tiek izsaukta Ŕī metode un karÅ”u attēli tiek paslēpti.

parādīts = nepatiess.

memoryGameDidEnd

Kad tiek izsaukta Ŕī metode, tas nozÄ«mē, ka visas kārtis jau ir atklātas un atrodas kārÅ”u sarakstāShown: cardsShown.count = cards.count, tātad spēle ir beigusies. Metode tiek Ä«paÅ”i izsaukta pēc tam, kad esam izsaukuÅ”i endGame(), lai iestatÄ«tu isPlaying var uz false, pēc tam tiek parādÄ«ts spēles beigu ziņojums. ArÄ« alertController tiek izmantots kā kontrollera indikators. Tiek izsaukts viewDidDisappar un spēle tiek atiestatÄ«ta.

Lūk, kā tas viss izskatās 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()
    }
}

Atmiņas karÅ”u spēles rakstÄ«Å”ana programmā Swift
PatiesÄ«bā tas arÄ« viss. Varat izmantot Å”o projektu, lai izveidotu savu spēles versiju.

Laimīgu kodēŔanu!

Skillbox iesaka:

Avots: www.habr.com

Pievieno komentāru