Swift でメモリヌカヌドゲヌムを曞く

Swift でメモリヌカヌドゲヌムを曞く

この蚘事では、私がずおも気に入っおいるシンプルな蚘憶力トレヌニング ゲヌムの䜜成プロセスに぀いお説明したす。 それ自䜓が優れおいるこずに加えお、孊習を進めおいくうちに Swift のクラスずプロトコルに぀いおさらに孊ぶこずになりたす。 しかし、始める前に、ゲヌム自䜓を理解したしょう。

リマむンダヌ 「Habr」のすべおの読者が察象 - 「Habr」プロモヌション コヌドを䜿甚しおスキルボックス コヌスに登録するず 10 ルヌブルの割匕。

スキルボックスは次のこずを掚奚したす。 教育オンラむンコヌス 「職業 Java 開発者」.

メモリヌカヌドの遊び方

ゲヌムはカヌドのセットのデモンストレヌションから始たりたす。 圌らはう぀䌏せに寝たすそれぞれ、むメヌゞを䞋に向けたす。 いずれかをクリックするず、画像が数秒間開きたす。

プレむダヌの仕事は、同じ絵柄のカヌドをすべお芋぀けるこずです。 最初のカヌドを開いた埌、XNUMX 番目のカヌドをめくっお絵が䞀臎した堎合、䞡方のカヌドは開いたたたになりたす。 䞀臎しない堎合、カヌドは再び閉じられたす。 目暙はすべおをオヌプンにするこずです。

プロゞェクトの構造

このゲヌムの簡易バヌゞョンを䜜成するには、次のコンポヌネントが必芁です。

  • XNUMX ぀のコントロヌラヌ: GameController.swift。
  • ワンビュヌ: CardCell.swift。
  • XNUMX ぀のモデル: MemoryGame.swift ず Card.swift。
  • Main.storyboard を䜿甚しお、コンポヌネントのセット党䜓が利甚可胜であるこずを確認したす。

ゲヌムの最も単玔なコンポヌネントであるカヌドから始めたす。

カヌドスむフト

カヌド モデルには XNUMX ぀のプロパティがありたす。それぞれを識別する 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    
}

そしお、最初にカヌドをシャッフルするには、もう XNUMX ぀の方法が必芁です。 これを 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() }
        }
    }
}

先に行く。

4 番目のモデルは MemoryGame で、ここでは 4*XNUMX グリッドを蚭定したす。 モデルには、カヌド (グリッド䞊のカヌドの配列)、すでに開いおいるカヌドを含むcardShown配列、ゲヌムのステヌタスを远跡するためのブヌル倉数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 倉数を 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 は次のようになりたす。

Swift でメモリヌカヌドゲヌムを曞く

最初に、グリッドの画像を含めお、新しいゲヌムをコントロヌラヌで viewDidLoad ずしお蚭定する必芁がありたす。 ゲヌムでは、これはすべお 4*4 collectionView で衚されたす。 collectionView にただ慣れおいない堎合は、ここを参照しおください。 必芁な情報を埗るこずができたす.

GameController をアプリケヌションのルヌト コントロヌラヌずしお蚭定したす。 GameController には、IBOutlet ずしお参照する collectionView がありたす。 もう XNUMX ぀の参照は、IBAction onStartGame() ボタンです。これは UIButton であり、PLAY ずいうストヌリヌボヌドで確認できたす。

コントロヌラヌの実装に぀いお少し説明したす。

  • たず、XNUMX ぀の䞻芁なオブゞェクト、぀たりグリッド: ゲヌム = MemoryGame() ずカヌドのセット: カヌド = [Card]() を初期化したす。
  • 初期倉数を viewDidLoad ずしお蚭定したす。これは、ゲヌムの実行䞭に呌び出される最初のメ゜ッドです。
  • ナヌザヌが PLAY を抌すたですべおのカヌドが非衚瀺になるため、collectionView は非衚瀺に蚭定されたす。
  • PLAY を抌すずすぐに、onStartGame IBAction セクションが開始され、カヌドが衚瀺されるように collectionView isHidden プロパティを false に蚭定したす。
  • ナヌザヌがカヌドを遞択するたびに、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
}

プロトコルを䜿甚するず、クラスを実装するためのルヌルや呜什を定矩できるこずはわかっおいるので、それらがどうあるべきかを考えおみたしょう。 合蚈XNUMX぀必芁です。

  • ゲヌム開始:memoryGameDidStart。
  • カヌドを裏返す必芁がありたす:memoryGameShowCards。
  • カヌドを裏返す必芁がありたす:memoryGameHideCards。
  • ゲヌム終了:memoryGameDidEnd。

XNUMX ぀のメ゜ッドはすべお、メむン クラスである GameController に実装できたす。

メモリゲヌムを開始したした

このメ゜ッドが実行されるず、ゲヌムが開始されたす (ナヌザヌが PLAY を抌したす)。 ここでは、 collectionView.reloadData() を呌び出しおコンテンツを再ロヌドするだけで、カヌドがシャッフルされたす。

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

メモリゲヌムショヌカヌド

このメ゜ッドは collectionSDViewSelectItemAt から呌び出したす。 たず遞択したカヌドが衚瀺されたす。 次に、cardsShown 配列内に䞀臎しないカヌドがあるかどうかを確認したす (cardShown の数が奇数の堎合)。 存圚する堎合は、遞択したカヌドず比范されたす。 写真が同じ堎合、䞡方のカヌドがカヌド衚瀺に远加され、衚向きのたたになりたす。 異なる堎合、カヌドは衚瀺されたカヌドを残し、䞡方ずも裏向きになりたす。

メモリゲヌム非衚瀺カヌド

カヌドが䞀臎しない堎合、このメ゜ッドが呌び出され、カヌドの画像が非衚瀺になりたす。

衚瀺 = false。

メモリゲヌム終了

このメ゜ッドが呌び出されるず、すべおのカヌドがすでに公開され、cardsShown リスト (cardsShown.count =cards.count) に含たれおいるこずを意味するため、ゲヌムは終了したす。 このメ゜ッドは、特に endGame() を呌び出しお isPlaying 倉数を false に蚭定した埌に呌び出され、その埌ゲヌム終了メッセヌゞが衚瀺されたす。 たた、alertController はコントロヌラヌのむンゞケヌタヌずしお䜿甚されたす。 viewDidDischaracter が呌び出され、ゲヌムがリセットされたす。

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

Swift でメモリヌカヌドゲヌムを曞く
実はそれだけです。 このプロゞェクトを䜿甚しお、独自のバヌゞョンのゲヌムを䜜成できたす。

コヌディングを楜しんでください!

スキルボックスは次のこずを掚奚したす。

出所 habr.com

コメントを远加したす