Este artigo describe o proceso de creación dun xogo sinxelo de adestramento da memoria que me gusta moito. Ademais de ser bo en si mesmo, aprenderás un pouco máis sobre as clases e os protocolos de Swift a medida que vaias. Pero antes de comezar, imos entender o xogo en si.
Recordámolo:para todos os lectores de "Habr" - un desconto de 10 rublos ao inscribirse en calquera curso de Skillbox usando o código promocional "Habr".
O xogo comeza cunha demostración dun conxunto de cartas. Déitanse boca abaixo (respectivamente, imaxe para abaixo). Cando fai clic en calquera, a imaxe ábrese durante uns segundos.
A tarefa do xogador é atopar todas as cartas coas mesmas imaxes. Se despois de abrir a primeira tarxeta, dás a volta á segunda e as imaxes coinciden, ambas as tarxetas permanecen abertas. Se non coinciden, pecharanse de novo as tarxetas. O obxectivo é abrir todo.
Estrutura do proxecto
Para crear unha versión sinxela deste xogo necesitas os seguintes compoñentes:
Un controlador: GameController.swift.
Unha vista: CardCell.swift.
Dous modelos: MemoryGame.swift e Card.swift.
Main.storyboard para garantir que todo o conxunto de compoñentes está dispoñible.
Comezamos polo compoñente máis sinxelo do xogo, as cartas.
Tarxeta.swift
O modelo de tarxeta terá tres propiedades: id para identificar cada unha, unha variable booleana mostrada para especificar o estado da tarxeta (oculta ou aberta) e artworkURL para as imaxes das tarxetas.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Tamén necesitará estes métodos para controlar a interacción do usuario cos mapas:
Método para mostrar unha imaxe nunha tarxeta. Aquí restablecemos todas as propiedades por defecto. Para id, xeramos un id aleatorio chamando a NSUUIS().uuidString.
O segundo modelo é MemoryGame, aquí establecemos unha cuadrícula 4*4. O modelo terá propiedades como tarxetas (unha matriz de cartas nunha cuadrícula), unha matriz cardsShown coas tarxetas xa abertas e unha variable booleana isPlaying para seguir o estado do xogo.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Tamén necesitamos desenvolver métodos para controlar a interacción do usuario coa rede.
Este método le o último elemento da matriz **cardsShown** e devolve a tarxeta que non coincide.
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 e GameController.swift
Main.storyboard parece algo así:
Inicialmente, debes configurar o novo xogo como viewDidLoad no controlador, incluídas as imaxes para a grella. No xogo, todo isto estará representado por 4*4 collectionView. Se aínda non estás familiarizado con collectionView, aquí está podes obter a información que necesites.
Configuraremos o GameController como controlador raíz da aplicación. O GameController terá unha collectionView á que faremos referencia como IBOutlet. Outra referencia é ao botón IBAction onStartGame(), este é un UIButton, podes velo no guión gráfico chamado PLAY.
Un pouco sobre a implementación dos controladores:
En primeiro lugar, inicializamos dous obxectos principais: a grella: xogo = Xogo de memoria() e un conxunto de tarxetas: tarxetas = [Tarxeta]().
Establecemos as variables iniciais como viewDidLoad, este é o primeiro método que se chama mentres o xogo está en execución.
collectionView está configurado como oculto porque todas as tarxetas están ocultas ata que o usuario preme REPRODUCIR.
En canto prememos PLAY, comeza a sección IBAction onStartGame e establecemos a propiedade collectionView isHidden como false para que as tarxetas poidan facerse visibles.
Cada vez que o usuario selecciona unha tarxeta, chámase ao método didSelectItemAt. No método que chamamos didSelectCard para implementar a lóxica do xogo principal.
Aquí está a implementación final de GameController:
Agora imos falar un pouco dos protocolos importantes.
Protocolos
Traballar con protocolos é o núcleo da programación de Swift. Os protocolos proporcionan a capacidade de definir regras para unha clase, estrutura ou enumeración. Este principio permítelle escribir código modular e extensible. De feito, este é un patrón que xa estamos implementando para collectionView en GameController. Agora imos facer a nosa propia versión. A sintaxe terá o seguinte aspecto:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Sabemos que un protocolo permítenos definir regras ou instrucións para implementar unha clase, así que pensemos cales deberían ser. Necesitas catro en total.
Inicio do xogo: memoryGameDidStart.
Debes xirar a tarxeta cara abaixo: memoryGameShowCards.
Debes xirar a tarxeta cara abaixo: memoryGameHideCards.
Fin do xogo: memoryGameDidEnd.
Os catro métodos pódense implementar para a clase principal, que é GameController.
memoryGameDidStart
Cando se executa este método, o xogo debería comezar (o usuario preme PLAY). Aquí simplemente recargaremos o contido chamando a collectionView.reloadData(), que barallará as tarxetas.
Chamamos a este método desde collectionSDViewSelectItemAt. Primeiro mostra a tarxeta seleccionada. Despois comproba se hai unha tarxeta non coincidente na matriz cardsShown (se o número de cardsShown é impar). Se hai un, a tarxeta seleccionada compárase con ela. Se as imaxes son iguais, as dúas tarxetas engádense ás tarxetas mostradas e permanecen boca arriba. Se é diferente, a tarxeta deixa as tarxetas mostradas e ambas bótanse boca abaixo.
MemoryGameHideCards
Se as tarxetas non coinciden, chámase a este método e escóndense as imaxes das tarxetas.
mostrado = falso.
memoryGameDidEnd
Cando se chama este método, significa que todas as cartas xa están reveladas e están na lista cardsShown: cardsShown.count = cards.count, polo que o xogo rematou. O método chámase especificamente despois de chamar a endGame() para establecer a isPlaying var como false, despois de que se mostra a mensaxe de finalización do xogo. Tamén alertController úsase como indicador para o controlador. chámase viewDidDisappear e restablece o xogo.
Aquí tes como se ve todo en 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()
}
}
En realidade, iso é todo. Podes usar este proxecto para crear a túa propia versión do xogo.