స్విఫ్ట్‌లో మెమరీ కార్డ్ గేమ్ రాయడం

స్విఫ్ట్‌లో మెమరీ కార్డ్ గేమ్ రాయడం

ఈ వ్యాసం నేను నిజంగా ఇష్టపడే సాధారణ మెమరీ శిక్షణ గేమ్‌ను సృష్టించే ప్రక్రియను వివరిస్తుంది. స్విఫ్ట్ క్లాస్‌లు మరియు ప్రోటోకాల్‌ల గురించి మీరు మరింత బాగా నేర్చుకుంటారు. కానీ మనం ప్రారంభించడానికి ముందు, ఆటను అర్థం చేసుకుందాం.

మేము గుర్తు చేస్తున్నాము: Habr పాఠకులందరికీ - Habr ప్రోమో కోడ్‌ని ఉపయోగించి ఏదైనా Skillbox కోర్సులో నమోదు చేసుకున్నప్పుడు 10 రూబుల్ తగ్గింపు.

Skillbox సిఫార్సు చేస్తోంది: ఎడ్యుకేషనల్ ఆన్‌లైన్ కోర్సు "వృత్తి జావా డెవలపర్".

మెమరీ కార్డ్ ప్లే ఎలా

గేమ్ కార్డుల సెట్ ప్రదర్శనతో ప్రారంభమవుతుంది. వారు ముఖం కింద పడుకుంటారు (వరుసగా, చిత్రం క్రిందికి). మీరు ఏదైనా ఒకదానిపై క్లిక్ చేసినప్పుడు, చిత్రం కొన్ని సెకన్ల పాటు తెరవబడుతుంది.

ఒకే చిత్రాలతో అన్ని కార్డులను కనుగొనడం ఆటగాడి పని. ఒకవేళ, మొదటి కార్డ్‌ని తెరిచిన తర్వాత, మీరు రెండవదాన్ని తిరగండి మరియు చిత్రాలు సరిపోలితే, రెండు కార్డ్‌లు తెరిచి ఉంటాయి. అవి సరిపోలకపోతే, కార్డులు మళ్లీ మూసివేయబడతాయి. ప్రతిదీ తెరవడమే లక్ష్యం.

ప్రాజెక్ట్ నిర్మాణం

ఈ గేమ్ యొక్క సరళమైన సంస్కరణను సృష్టించడానికి మీకు ఈ క్రింది భాగాలు అవసరం:

  • ఒక కంట్రోలర్: GameController.swift.
  • ఒక వీక్షణ: CardCell.swift.
  • రెండు మోడల్‌లు: MemoryGame.swift మరియు Card.swift.
  • Main.storyboard మొత్తం భాగాలు అందుబాటులో ఉన్నాయని నిర్ధారించడానికి.

మేము ఆట యొక్క సరళమైన భాగం, కార్డ్‌లతో ప్రారంభిస్తాము.

Card.swift

కార్డ్ మోడల్ మూడు లక్షణాలను కలిగి ఉంటుంది: ప్రతి ఒక్కటి గుర్తించడానికి id, కార్డ్ స్థితిని (దాచిన లేదా తెరిచి) పేర్కొనడానికి చూపబడే బూలియన్ వేరియబుల్ మరియు కార్డ్‌లలోని చిత్రాల కోసం ఆర్ట్‌వర్క్URL.

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

మ్యాప్‌లతో వినియోగదారు పరస్పర చర్యను నియంత్రించడానికి మీకు ఈ పద్ధతులు కూడా అవసరం:

కార్డ్‌పై చిత్రాన్ని ప్రదర్శించే విధానం. ఇక్కడ మేము అన్ని లక్షణాలను డిఫాల్ట్‌గా రీసెట్ చేస్తాము. id కోసం, మేము NSUUIS().uuidStringకి కాల్ చేయడం ద్వారా యాదృచ్ఛిక IDని రూపొందిస్తాము.

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

ID కార్డులను పోల్చడానికి పద్ధతి.

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    
}

మరియు ప్రారంభంలో కార్డ్‌లను షఫుల్ చేయడానికి మరొక పద్ధతి అవసరం. మేము దానిని అర్రే తరగతికి పొడిగింపుగా చేస్తాము.

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

మరియు అన్ని లక్షణాలు మరియు పద్ధతులతో కార్డ్ మోడల్ కోసం కోడ్ యొక్క అమలు ఇక్కడ ఉంది.

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 గ్రిడ్‌ను సెట్ చేసాము. మోడల్‌లో కార్డ్‌లు (గ్రిడ్‌లోని కార్డ్‌ల శ్రేణి), ఇప్పటికే తెరిచిన కార్డ్‌లతో చూపబడిన కార్డ్‌ల శ్రేణి మరియు గేమ్ స్థితిని ట్రాక్ చేయడానికి బూలియన్ వేరియబుల్ 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 వేరియబుల్‌ని trueకి ప్రారంభించే మొదటి పద్ధతిని ఇక్కడ మేము పిలుస్తాము.

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

మేము ఆటను పునఃప్రారంభించాలనుకుంటే, అప్పుడు మేము isPlaying వేరియబుల్‌ను తప్పుగా సెట్ చేస్తాము మరియు కార్డ్‌ల ప్రారంభ లేఅవుట్‌ను తీసివేస్తాము.

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 సేకరణ వీక్షణ ద్వారా సూచించబడతాయి. సేకరణ వీక్షణ గురించి మీకు ఇంకా తెలియకపోతే, ఇదిగోండి మీకు అవసరమైన సమాచారాన్ని మీరు పొందవచ్చు.

మేము గేమ్‌కంట్రోలర్‌ని అప్లికేషన్ యొక్క రూట్ కంట్రోలర్‌గా కాన్ఫిగర్ చేస్తాము. గేమ్‌కంట్రోలర్‌లో కలెక్షన్‌వ్యూ ఉంటుంది, దానిని మేము IBOutletగా సూచిస్తాము. మరొక సూచన IBAction onStartGame() బటన్, ఇది UIButton, మీరు దీన్ని PLAY అనే స్టోరీబోర్డ్‌లో చూడవచ్చు.

కంట్రోలర్ల అమలు గురించి కొంచెం:

  • ముందుగా, మేము రెండు ప్రధాన వస్తువులను ప్రారంభించాము - గ్రిడ్: గేమ్ = MemoryGame(), మరియు కార్డ్‌ల సమితి: కార్డ్‌లు = [కార్డ్]().
  • మేము ప్రారంభ వేరియబుల్స్‌ను viewDidLoadగా సెట్ చేసాము, ఇది గేమ్ నడుస్తున్నప్పుడు పిలువబడే మొదటి పద్ధతి.
  • సేకరణView దాచబడినట్లుగా సెట్ చేయబడింది ఎందుకంటే వినియోగదారు PLAY నొక్కే వరకు అన్ని కార్డ్‌లు దాచబడతాయి.
  • మేము PLAY నొక్కిన వెంటనే, onStartGame IBAction విభాగం ప్రారంభమవుతుంది మరియు కార్డ్‌లు కనిపించేలా కలెక్షన్‌వ్యూ isHidden ఆస్తిని తప్పుగా సెట్ చేస్తాము.
  • వినియోగదారు కార్డ్‌ని ఎంచుకున్న ప్రతిసారి, didSelectItemAt పద్ధతి అంటారు. ప్రధాన గేమ్ లాజిక్‌ను అమలు చేయడానికి మేము didSelectCard అని పిలుస్తున్న పద్ధతిలో.

చివరి గేమ్‌కంట్రోలర్ అమలు ఇక్కడ ఉంది:

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

ఇప్పుడు ముఖ్యమైన ప్రోటోకాల్‌ల గురించి కొంచెం మాట్లాడుకుందాం.

ప్రోటోకాల్లు

ప్రోటోకాల్‌లతో పనిచేయడం స్విఫ్ట్ ప్రోగ్రామింగ్ యొక్క ప్రధాన అంశం. ప్రోటోకాల్‌లు తరగతి, నిర్మాణం లేదా గణన కోసం నియమాలను నిర్వచించే సామర్థ్యాన్ని అందిస్తాయి. ఈ సూత్రం మాడ్యులర్ మరియు ఎక్స్‌టెన్సిబుల్ కోడ్‌ను వ్రాయడానికి మిమ్మల్ని అనుమతిస్తుంది. వాస్తవానికి, ఇది గేమ్‌కంట్రోలర్‌లో సేకరణ వీక్షణ కోసం మేము ఇప్పటికే అమలు చేస్తున్న నమూనా. ఇప్పుడు మన స్వంత సంస్కరణను తయారు చేద్దాం. వాక్యనిర్మాణం ఇలా కనిపిస్తుంది:

protocol MemoryGameProtocol {
    //protocol definition goes here
}

తరగతిని అమలు చేయడానికి నియమాలు లేదా సూచనలను నిర్వచించడానికి ప్రోటోకాల్ అనుమతిస్తుంది అని మాకు తెలుసు, కాబట్టి అవి ఎలా ఉండాలో ఆలోచిద్దాం. మీకు మొత్తం నాలుగు కావాలి.

  • గేమ్ ప్రారంభం: మెమరీGameDidStart.
  • మీరు కార్డ్ ముఖాన్ని క్రిందికి తిప్పాలి: memoryGameShowCards.
  • మీరు కార్డ్ ముఖాన్ని క్రిందికి తిప్పాలి: memoryGameHideCards.
  • గేమ్ ముగింపు: memoryGameDidEnd.

గేమ్‌కంట్రోలర్ అయిన ప్రధాన తరగతికి నాలుగు పద్ధతులను అమలు చేయవచ్చు.

memoryGameDidStart

ఈ పద్ధతిని అమలు చేసినప్పుడు, గేమ్ ప్రారంభం కావాలి (వినియోగదారు ప్లే నొక్కండి). ఇక్కడ మేము సేకరణView.reloadData()కి కాల్ చేయడం ద్వారా కంటెంట్‌ను రీలోడ్ చేస్తాము, ఇది కార్డ్‌లను షఫుల్ చేస్తుంది.

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

మెమరీగేమ్ షోకార్డులు

మేము సేకరణSDViewSelectItemAt నుండి ఈ పద్ధతిని పిలుస్తాము. మొదట ఇది ఎంచుకున్న కార్డును చూపుతుంది. ఆపై కార్డ్‌లు చూపబడిన శ్రేణిలో సరిపోలని కార్డ్ ఉందో లేదో తనిఖీ చేస్తుంది (కార్డుల సంఖ్య బేసిగా ఉంటే). ఒకటి ఉంటే, ఎంచుకున్న కార్డ్ దానితో పోల్చబడుతుంది. చిత్రాలు ఒకేలా ఉంటే, రెండు కార్డ్‌లు చూపబడిన కార్డ్‌లకు జోడించబడతాయి మరియు ముఖాముఖిగా ఉంటాయి. భిన్నంగా ఉంటే, కార్డ్ కార్డ్‌లను చూపుతుంది మరియు రెండూ ముఖం క్రిందికి తిప్పబడతాయి.

memoryGameHideCards

కార్డులు సరిపోలకపోతే, ఈ పద్ధతిని పిలుస్తారు మరియు కార్డ్ చిత్రాలు దాచబడతాయి.

చూపిన = తప్పుడు.

memoryGameDidEnd

ఈ పద్ధతిని పిలిచినప్పుడు, అన్ని కార్డ్‌లు ఇప్పటికే వెల్లడి చేయబడ్డాయి మరియు కార్డ్‌లు చూపబడిన జాబితాలో ఉన్నాయని అర్థం: cardsShown.count = cards.count, కాబట్టి ఆట ముగిసింది. isPlaying varని తప్పుగా సెట్ చేయడానికి మేము endGame() అని పిలిచిన తర్వాత ఈ పద్ధతిని ప్రత్యేకంగా పిలుస్తారు, ఆ తర్వాత గేమ్ ముగింపు సందేశం చూపబడుతుంది. అలాగే అలర్ట్‌కంట్రోలర్ నియంత్రికకు సూచికగా ఉపయోగించబడుతుంది. viewDidDisappear అంటారు మరియు గేమ్ రీసెట్ చేయబడింది.

గేమ్‌కంట్రోలర్‌లో ఇదంతా ఎలా ఉంటుందో ఇక్కడ ఉంది:

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

ఒక వ్యాఖ్యను జోడించండి