#13 — Black Jack 二十一點x辛普森翻牌記憶遊戲

呈現畫面:

此遊戲包含了三個畫面,單純選擇遊戲的ViewController、 Black Jack 21點以及記憶翻牌遊戲,其中總資產會利用頁面傳值、Protocol的方式來回傳遞。(當你玩21點玩到破產時,只能去玩記憶翻牌遊戲把錢賺回來~)

先來說說21點,利用迴圈產生撲克牌代碼並存入一個陣列中搭配shuffle()洗牌,再將撲克牌圖片名稱都改成一樣的代碼就可以得到完整得一副牌了。

(此網站可免費提供別人設計的優質卡牌圖片)

此遊戲中比較特別的是Ace的點數有可能是1或11,但要在什麼情況當作1點或11點呢?

我的作法如下:

只要當前點數總和<11點,Ace就會當成11點,而playerEleven = true 代表當過11點。

//計算player點數
func myScore(){
switch cards[0].rank{
case "J","Q","K":
playerScore += 10
case "A":
if playerScore < 11{
playerScore += 11
playerEleven = true
}else{
playerScore += 1
}
default:
playerScore += Int(cards[0].rank)!
}
}

如果手牌有包含Ace且超過21點、playerEleven = true的話,就減10點。

(playerOnce = false代表減過一次10點,不能再使用了)

if playerOnce == true{
if playerScore > 21&&playerCards.contains("A")&&playerEleven == true{
playerScore -= 10
playerOnce = false
}
}

每當要牌時,都是取cards卡牌陣列中的第[0]張,取完再cards.removeFirst()移除掉,下一張再循環此方式。

//要牌
@IBAction func callButton(_ sender: UIButton) {
stepperOutlet.isHidden = true
allInOutlet.isHidden = true
stopOutlet.isHidden = false
giveUpOutlet.isHidden = false

if cardImageNum == 0{
firstServe()
}else if cardImageNum < 4{
let animator = UIViewPropertyAnimator(duration: 1.5, curve: .linear) {
self.playerCardImage[self.cardImageNum].alpha = 1
}
animator.startAnimation()
playerCardImage[cardImageNum].image = UIImage(named:cards[0].suits + cards[0].rank )
myScore()
playerCards.append(cards[0].rank)
if playerOnce == true{
if playerScore > 21&&playerCards.contains("A")&&playerEleven == true{
playerScore -= 10
playerOnce = false
}
}
playerScoreLabel.text = "\(playerScore)"
cards.removeFirst()
cardImageNum += 1
playerCheck()
mus()
}else if cardImageNum == 4{

let animator = UIViewPropertyAnimator(duration: 1.5, curve: .linear) {
self.playerCardImage[self.cardImageNum].alpha = 1
}
animator.startAnimation()

playerCardImage[cardImageNum].image = UIImage(named:cards[0].suits + cards[0].rank )
myScore()
playerCards.append(cards[0].rank)
if playerOnce == true{
if playerScore > 21&&playerCards.contains("A")&&playerEleven == true{
playerScore -= 10
playerOnce = false
}
}

playerScoreLabel.text = "\(playerScore)"
cards.removeFirst()
if playerScore < 22{
resultLabel.text = "過五關"
playerResult(win: true, odds: 3)
hidden()
reset()
}else{
playerCheck()
}
mus()
}
}

莊家則是不足17點且不足五張時,用while迴圈重複抽牌。

//停止要牌
@IBAction func stopButton(_ sender: UIButton) {

let animator = UIViewPropertyAnimator(duration: 1.5, curve: .linear) {
self.secretImage.alpha = 0
}
animator.startAnimation()
cardImageNum = 2
hidden()
if bankerScore < 17{
while bankerScore < 17&&cardImageNum < 5{

let animator = UIViewPropertyAnimator(duration: 1.5, curve: .linear) {
self.bankerCardImage[self.cardImageNum].alpha = 1
}
animator.startAnimation()

bankerCardImage[cardImageNum].image = UIImage(named:cards[0].suits + cards[0].rank)
computerScore()
bankerCards.append(cards[0].rank)
if bankerOnce == true{
if bankerScore > 21&&bankerCards.contains("A")&&bankerEleven == true{
bankerScore -= 10
bankerOnce = false
}
}
cards.removeFirst()
cardImageNum += 1
mus()
}
bankerScoreLabel.text = "\(bankerScore)"
bankerCheck()
}else{
bankerScoreLabel.text = "\(bankerScore)"
bankerCheck()
}
}

值得注意的是破產時我設定會直接利用navigationController?.popViewController(animated: true)回到上一頁,當我回到上一頁時我要顯示剩餘資產就必須要回傳資料。

//確認是否資金不足
func checkBankrupt(){
if totalMoney < 1000&&bet == 0{
let Alert = UIAlertController(title: "資金不足!!", message: "去借點錢再來賭吧", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default) { [self] UIAlertAction in
navigationController?.popViewController(animated: true)
}
Alert.addAction(action)
present(Alert, animated: true)
}
}

在popViewController或點選左上角的Navigation Item(back)回去第一個頁面前都會先經過viewWillDisappear的生命週期所以我直接把回傳資料寫在了viewWillDisappear裡面。

var delegate:SentBackData?override func viewWillDisappear(_ animated: Bool) {
delegate?.dissmissback(data: totalMoney + bet)
}

關於利用協定回傳資料的方法:

參考資料:

翻牌遊戲的牌組同理一樣利用迴圈產生並加入陣列中洗牌。

先將解答展示,兩秒過後全部設置為背面Image。

for i in 0...simpsonsOutlet.count-1{
simpsonsOutlet[i].setImage(simpsons[i].image, for: .normal)
simpsonsOutlet[i].alpha = 1
UIView.transition(with: simpsonsOutlet[i], duration: 0.5, options: .transitionFlipFromRight, animations: nil, completion: nil)
mus(name: "456")
}
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { [self] _ in
for i in 0...simpsonsOutlet.count-1{
simpsonsOutlet[i].setImage(UIImage(named: "back"), for: .normal)
UIView.transition(with: simpsonsOutlet[i], duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
mus(name: "456")
startgame(go:true)
}
}

設定點擊button就翻牌的功能。(正面就變成背面、背面就變成正面)

//翻牌轉換
func flop(index:Int){
if simpsons[index].isFlipped == true{
simpsonsOutlet[index].setImage(UIImage(named: "back"), for: .normal)
UIView.transition(with: simpsonsOutlet[index], duration: 0.5, options: .transitionFlipFromLeft, animations: nil, completion: nil)
simpsons[index].isFlipped = false
}else{
simpsonsOutlet[index].setImage(simpsons[index].image, for: .normal)
UIView.transition(with: simpsonsOutlet[index], duration: 0.5, options: .transitionFlipFromRight, animations: nil, completion: nil)
simpsons[index].isFlipped = true
}
}

開始翻牌時就先倒數時間,利用計時器每過一秒就執行upDateTime()的function。

@IBAction func simpsonsButton(_ sender: UIButton) {
//開始倒數
if time == nil{
time = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(upDateTime), userInfo: nil, repeats: true)
}

(預設seconds = 60,當減到剩0時會顯示挑戰失敗的UIAlertController)

//每過一秒執行此func
@objc func upDateTime(){
seconds -= 1
if seconds == 0{
time?.invalidate()
let alert = UIAlertController(title: "挑戰失敗", message: "輸家是沒有獎金的", preferredStyle: .alert)
let action = UIAlertAction(title: "ok", style: .default) { [self] UIAlertAction in
reset()
}
alert.addAction(action)
present(alert, animated: true)
}
timeLabel.text = "\(seconds)"
}

當翻出一樣的牌時,透明度會變為0.5且simpsons[index].isAlive = false代表死亡不能再被點擊。

//判斷如果是相同圖案就死掉並且改變透明度
func sameImage(index:Int){
simpsons[index].isAlive = false
simpsonsOutlet[index].alpha = 0.5
UIView.transition(with: simpsonsOutlet[index], duration: 0.5, options: .transitionFlipFromRight, animations: nil, completion: nil)
}

主要程式碼如下:

(點擊開始倒數 →simpsonsOutlet.firstIndex(of: sender)將點擊到的數字存到index →判斷button是否死亡 →numArray陣列判斷翻牌的張數,最多翻兩張→simpsons[numArray[0]].number、simpsons[numArray[1]].number是否相同,無論相同與否都會利用迴圈搭配numArray陣列,差別在於相同呼叫sameImage(index:Int),不相同則呼叫flop(index:Int))

@IBAction func simpsonsButton(_ sender: UIButton) {
//開始倒數
if time == nil{
time = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(upDateTime), userInfo: nil, repeats: true)
}

if let index = simpsonsOutlet.firstIndex(of: sender){
if simpsons[index].isAlive == false{
return
}
if numArray.count == 0{
flop(index: index)
numArray.append(index)
mus(name: "456")
//numArray.count == 1 限制翻完兩張不能馬上翻第三張
}else if numArray.count == 1{
if numArray.contains(index){
flop(index: index)
numArray.removeAll()
mus(name: "456")
}else{
mus(name: "456")
flop(index: index)
numArray.append(index)
if simpsons[numArray[0]].number == simpsons[numArray[1]].number{
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { [self] _ in
for i in numArray{
sameImage(index: i)
mus2(name: "correct")
}
numArray.removeAll()
finishNum += 1
if finishNum == 8{
time?.invalidate()
if seconds > 39 {
let alert = UIAlertController(title: "太神啦!!", message: "恭喜你獲得$30000", preferredStyle: .alert)
let action = UIAlertAction(title: "ok", style: .default) { [self] UIAlertAction in
totalMoney += 30000
totalLabel.text = "$\(totalMoney)"
reset()
}
alert.addAction(action)
present(alert, animated: true)
}else if seconds > 19{
let alert = UIAlertController(title: "太厲害了!!", message: "恭喜你獲得$10000", preferredStyle: .alert)
let action = UIAlertAction(title: "ok", style: .default) { [self] UIAlertAction in
totalMoney += 10000
totalLabel.text = "$\(totalMoney)"
reset()
}
alert.addAction(action)
present(alert, animated: true)
}else{
let alert = UIAlertController(title: "不錯哦!!", message: "恭喜你獲得$5000", preferredStyle: .alert)
let action = UIAlertAction(title: "ok", style: .default) { [self] UIAlertAction in
totalMoney += 5000
totalLabel.text = "$\(totalMoney)"
reset()
}
alert.addAction(action)
present(alert, animated: true)
}
}
}
}else{
Timer.scheduledTimer(withTimeInterval: 0.7, repeats: false) { [self] _ in
for (_,num) in numArray.enumerated(){
flop(index: num)
}
numArray.removeAll()
}
}
}
}
}
}

參考資料:

GitHub網址:

--

--