Bài viết này mô tả quá trình tạo ra một trò chơi rèn luyện trí nhớ đơn giản mà tôi rất thích. Bên cạnh việc bản thân nó đã tốt, bạn sẽ tìm hiểu thêm một chút về các lớp và giao thức Swift trong quá trình học. Nhưng trước khi bắt đầu, chúng ta hãy hiểu bản thân trò chơi.
Chúng tôi nhắc nhở:cho tất cả độc giả của "Habr" - giảm giá 10 rúp khi đăng ký bất kỳ khóa học Skillbox nào bằng mã khuyến mại "Habr".
Trò chơi bắt đầu bằng việc trình diễn một bộ thẻ. Họ nằm úp mặt (tương ứng, hình ảnh úp xuống). Khi bạn nhấp vào bất kỳ cái nào, hình ảnh sẽ mở ra trong vài giây.
Nhiệm vụ của người chơi là tìm tất cả các thẻ có hình giống nhau. Nếu sau khi mở thẻ đầu tiên, bạn lật thẻ thứ hai và các hình ảnh giống nhau thì cả hai thẻ vẫn mở. Nếu chúng không khớp, các thẻ sẽ bị đóng lại. Mục tiêu là để mở mọi thứ.
Cấu trúc dự án
Để tạo một phiên bản đơn giản của trò chơi này, bạn cần có các thành phần sau:
Một bộ điều khiển: GameController.swift.
Một chế độ xem: CardCell.swift.
Hai mô hình: MemoryGame.swift và Card.swift.
Main.storyboard để đảm bảo rằng toàn bộ bộ thành phần đều có sẵn.
Chúng ta bắt đầu với thành phần đơn giản nhất của trò chơi, các lá bài.
Thẻ.swift
Mô hình thẻ sẽ có ba thuộc tính: id để xác định từng thuộc tính, một biến boolean được hiển thị để chỉ định trạng thái của thẻ (ẩn hoặc mở) và tác phẩm nghệ thuậtURL cho hình ảnh trên thẻ.
class Card {
var id: String
var shown: Bool = false
var artworkURL: UIImage!
}
Bạn cũng sẽ cần những phương pháp này để kiểm soát sự tương tác của người dùng với bản đồ:
Phương pháp hiển thị hình ảnh trên thẻ. Ở đây chúng tôi đặt lại tất cả các thuộc tính về mặc định. Đối với id, chúng tôi tạo một id ngẫu nhiên bằng cách gọi NSUUIS().uuidString.
Mô hình thứ hai là MemoryGame, ở đây chúng tôi đặt lưới 4*4. Mô hình sẽ có các thuộc tính như thẻ (một mảng thẻ trên lưới), mảng thẻHiển thị với các thẻ đã mở và biến boolean isPlaying để theo dõi trạng thái của trò chơi.
class MemoryGame {
var cards:[Card] = [Card]()
var cardsShown:[Card] = [Card]()
var isPlaying: Bool = false
}
Chúng ta cũng cần phát triển các phương pháp để kiểm soát sự tương tác của người dùng với lưới.
Phương thức này đọc phần tử cuối cùng trong mảng **cardsShown** và trả về thẻ không khớp.
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 và GameController.swift
Main.storyboard trông giống như thế này:
Ban đầu, bạn cần đặt trò chơi mới là viewDidLoad trong bộ điều khiển, bao gồm cả hình ảnh cho lưới. Trong trò chơi, tất cả những điều này sẽ được thể hiện bằng bộ sưu tập 4*4. Nếu bạn chưa quen với CollectionView thì đây bạn có thể nhận được thông tin bạn cần.
Chúng tôi sẽ định cấu hình GameController làm bộ điều khiển gốc của ứng dụng. GameController sẽ có một CollectionView mà chúng ta sẽ tham chiếu dưới dạng IBOutlet. Một tài liệu tham khảo khác là nút IBAction onStartGame(), đây là UIButton, bạn có thể thấy nó trong bảng phân cảnh có tên PLAY.
Một chút về việc thực hiện bộ điều khiển:
Đầu tiên, chúng ta khởi tạo hai đối tượng chính - lưới: game = MemoryGame() và một bộ thẻ: cards = [Card]().
Chúng tôi đặt các biến ban đầu là viewDidLoad, đây là phương thức đầu tiên được gọi khi trò chơi đang chạy.
CollectionView được đặt thành ẩn vì tất cả các thẻ đều bị ẩn cho đến khi người dùng nhấn PLAY.
Ngay sau khi chúng ta nhấn PLAY, phần IBAction onStartGame sẽ bắt đầu và chúng ta đặt thuộc tính CollectionView isHidden thành false để các thẻ có thể hiển thị.
Mỗi lần người dùng chọn một thẻ, phương thức didSelectItemAt sẽ được gọi. Trong phương thức này, chúng tôi gọi didSelectCard để triển khai logic trò chơi chính.
Bây giờ hãy nói một chút về các giao thức quan trọng.
Các giao thức
Làm việc với các giao thức là cốt lõi của lập trình Swift. Các giao thức cung cấp khả năng xác định các quy tắc cho một lớp, cấu trúc hoặc bảng liệt kê. Nguyên tắc này cho phép bạn viết mã mô-đun và có thể mở rộng. Trên thực tế, đây là mẫu mà chúng tôi đã triển khai cho CollectionView trong GameController. Bây giờ hãy tạo phiên bản của riêng chúng ta. Cú pháp sẽ trông như thế này:
protocol MemoryGameProtocol {
//protocol definition goes here
}
Chúng ta biết rằng một giao thức cho phép chúng ta xác định các quy tắc hoặc hướng dẫn để triển khai một lớp, vì vậy hãy suy nghĩ xem chúng nên như thế nào. Tổng cộng bạn cần bốn cái.
Bắt đầu trò chơi: MemoryGameDidStart.
Bạn cần úp lá bài úp xuống: MemoryGameShowCards.
Bạn cần úp thẻ úp xuống: MemoryGameHideCards.
Trò chơi kết thúc: MemoryGameDidEnd.
Tất cả bốn phương thức đều có thể được triển khai cho lớp chính, đó là GameController.
bộ nhớGameDidStart
Khi phương thức này được chạy, trò chơi sẽ bắt đầu (người dùng nhấn PLAY). Ở đây chúng ta chỉ cần tải lại nội dung bằng cách gọi CollectionView.reloadData(), thao tác này sẽ xáo trộn các thẻ.
Chúng tôi gọi phương thức này từ bộ sưu tậpSDViewSelectItemAt. Đầu tiên nó hiển thị thẻ đã chọn. Sau đó kiểm tra xem có thẻ nào chưa khớp trong mảng cardsShown hay không (nếu số lượng thẻShown là số lẻ). Nếu có, thẻ đã chọn sẽ được so sánh với thẻ đó. Nếu các hình ảnh giống nhau, cả hai thẻ sẽ được thêm vào thẻ Hiển thị và vẫn ngửa. Nếu khác nhau, thẻ để lại thẻ Hiển thị và cả hai đều úp xuống.
bộ nhớTrò chơiẨnThẻ
Nếu các thẻ không khớp, phương thức này được gọi và hình ảnh thẻ sẽ bị ẩn.
hiển thị = sai.
bộ nhớGameDidEnd
Khi phương thức này được gọi, điều đó có nghĩa là tất cả các thẻ đã được tiết lộ và nằm trong danh sách thẻHiển thị: cardsShown.count = cards.count, vậy là trò chơi kết thúc. Phương thức này được gọi cụ thể sau khi chúng ta gọi endGame() để đặt biến isPlaying thành false, sau đó thông báo kết thúc trò chơi sẽ được hiển thị. Ngoài ra, AlertController còn được sử dụng làm chỉ báo cho bộ điều khiển. viewDidDisappear được gọi và trò chơi được đặt lại.
Đây là những gì nó trông giống như trong 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()
}
}
Trên thực tế, đó là tất cả. Bạn có thể sử dụng dự án này để tạo phiên bản trò chơi của riêng mình.