
本文介绍了创建我真正喜欢的简单记忆训练游戏的过程。 除了本身出色外,您还将在工作中学到更多有关Swift类和协议的知识。 但是在开始之前,让我们先弄清楚游戏本身。
我们提醒您: 对于所有“哈勃”读者来说,使用“哈勃”促销代码注册任何Skillbox课程时均可享受10,000卢布的折扣。
Skillbox建议:在线教育课程“专业Java开发人员” 。
如何玩记忆卡
游戏从一组纸牌的演示开始。 他们躺在“衬衫”上(分别朝下)。 当您单击任何一个时,图像将打开几秒钟。
玩家的任务是找到所有带有相同图片的卡。 如果在打开第一张卡后将您的第二张翻过来并且图片匹配,则两张卡都保持打开状态。 如果它们不匹配,则再次关闭卡。 任务是打开所有内容。
项目结构
为了创建此游戏的简单版本,您需要以下组件:
- 一个控制器:GameController.swift。
- 一种视图:CardCell.swift。
- 两种模型:MemoryGame.swift和Card.swift。
- Main.storyboard,以便可以使用整个组件集。
我们从游戏中最简单的部分开始,即纸牌。
卡速证卡模型将具有三个属性:用于标识每个证件的ID,显示的用于阐明证卡状态(隐藏或打开)的逻辑变量,以及证卡上图片的artworkURL。
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 }
比较身份证的方法。 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初始化为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看起来像这样:

最初,在控制器中,您需要安装一个新游戏作为viewDidLoad,其中包括网格的图像。 在游戏中,所有这些将由4 * 4 collectionView表示。 如果您不熟悉collectionView,
则可以在此处
获取必要的信息 。
我们将GameController配置为应用程序的根控制器。 GameController中将有一个collectionView,我们将其称为IBOutlet。 另一个链接是IBAction onStartGame()按钮,它是UIButton,您可以在名为PLAY的情节提要中看到它。
关于控制器的实现:
- 首先,我们初始化两个主要对象-网格(游戏):游戏= MemoryGame(),并在卡片组上:卡片= [卡片]()。
- 将初始变量设置为viewDidLoad,这是游戏期间调用的第一个方法。
- 将collectionView设置为隐藏,因为所有地图都被隐藏,直到用户按下PLAY。
- 按下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 {
现在,让我们来谈谈一些重要的协议。
通讯协定
使用协议是Swift编程的基础。 协议提供了为类,结构或枚举设置规则的能力。 该原理使您可以编写模块化和可扩展的代码。 这实际上是我们已经为GameController中的collectionView实现的模板。 现在让我们制作自己的版本。 语法如下所示:
protocol MemoryGameProtocol {
我们知道,协议允许您定义用于实现类的规则或说明,因此让我们考虑一下它们应该是什么。 只需要四个。
- 游戏开始:memoryGameDidStart。
- 需要将卡正面朝下翻转:memoryGameShowCards。
- 需要将卡正面朝下翻转:memoryGameHideCards。
- 游戏完成:memoryGameDidEnd。
我们为主类实现了所有四个方法,这就是GameController。
memoryGameDidStart
启动此方法后,游戏应开始(用户按PLAY)。 在这里,我们只是简单地通过调用collectionView.reloadData()重新加载内容,这将导致地图混乱。
func memoryGameDidStart(_ game: MemoryGame) { collectionView.reloadData() }
memoryGameShowCards
从collectionSDViewSelectItemAt调用此方法。 首先,它显示选定的地图。 然后,它检查一下cardsShown数组中是否有不匹配的卡片(如果cardsShown的数目为奇数)。 如果有一张,则将所选卡与其进行比较。 如果图片相同,则将两张卡都添加到cardsShown中并保持打开状态。 如果不同,则卡片离开显示的卡片,并且两边都翻转过来。
memoryGameHideCards
如果卡片不匹配,则调用此方法,并且卡片图像被隐藏。
显示=假。
memoryGameDidEnd
调用此方法时,这意味着所有卡都已打开并且在cardsShown列表中:cardsShown.count = cards.count,因此游戏结束了。 在调用endGame()将isPlaying var设置为false之后,将特别调用该方法,然后显示有关游戏完成的消息。 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建议: