#43 叢林冒險 選擇題 App

Rose
彼得潘的 Swift iOS / Flutter App 開發教室
10 min readMay 14, 2021

學習變數,for & while 迴圈,if else ,array,類別和物件,亂數,自訂資料型別,viewDidLoad,outlet & action。

基本功能

  • 製作選擇題 App,每題有四個選項。
  • 答對一題加 10 分 。
  • 畫面上顯示目前題目是第幾題。
  • 自訂資料型別。
  • 題庫有 n 題,隨機出其中的 10 題,每次玩的時候題目順序都不一樣。( n > 10 )
  • 玩完後可選擇再玩一次,重新開始玩。
  • 同一頁顯示問題跟分數。

進階功能

  • 每題四個選項的順序不固定。
  • 分成問題頁跟分數頁,將結果從問題頁傳到分數頁。利用 IBSegueAction & PerformSegue。

APP規劃

定位為製作給小朋友辨別動物的選擇題APP

struct

新增File 命名 Question.swift 來存放問題

設定常數

import Foundationstruct Question {
//問題圖片
let questionImage: String

// 問題文字
let description: String

// 答案選項
let option: [String]

// 正確答案
let answer: String
}

建立 Label 的IBOutlet

// 第N題
@IBOutlet weak var itemNumber: UILabel!
// 分數
@IBOutlet weak var scoreLabel: UILabel!
// 題目圖片
@IBOutlet weak var questionImage: UIImageView!

// 選擇題按鈕
@IBOutlet var answerButton: [UIButton]!

建立選擇題按鈕,connection 選擇 Outlet Collection

可以一次連結四顆按鈕

有沒有發現第二顆的大象按鈕顏色比較深,後來才發現拉到二次 IBOulet 導致第二顆一直出不來

設定拿來存放資料的變數

// 題目數量
var index = 0

// 分數
var score = 0

// 正確答案
var rightAnswer = ""
// 題目與答案
var questionData = [
Question(image: "question-豬", description: "豬", option: ["馬","牛","豬","羊"], answer: "豬"),
Question(image: "question-大象", description: "大象", option: ["大象","老鼠","河馬","牛"], answer: "大象"),
Question(image: "question-火鶴", description: "火鶴", option: ["雞","獅子","火鶴","鱷魚"], answer: "火鶴"),
Question(image: "question-牛", description: "火鶴", option: ["牛","鴨子","蛇","老鼠"], answer: "牛")
]

建立按鈕 IBAction

因為 function 還沒建立,所以內容先留空

// 選擇題按鈕
@IBAction func answerClick(_ sender: UIButton) {

}

// 再玩一次
@IBAction func restartClick(_ sender: UIButton) {

}

設定遊戲開始

@IBAction func answerClick(_ sender: UIButton) {
index = index + 1

// 如果選擇的按鈕上的文字 等於 正確答案
if sender.currentTitle == rightAnswer{
//分數加10分
score = score + 10
//顯示到Label上
scoreLabel.text = "\(score)"
}

// 在10題之內進行遊戲,或是計算總分
if index < 10{
startGame()
} else {
totalScore()
}
}
// 遊戲開始
func startGame() {
//題目
itemNumber.text = String(index + 1)
//問題圖片
questionImage.image = UIImage(named: questionData[index].image)
//正確答案
rightAnswer = questionData[index].answer
//4個選擇題亂數排列
questionData[index].option.shuffle()

//設定選擇題按鈕文字
for i in 0...3{
answerButton[i].setTitle(questionData[index].option[i], for: .normal)
}
}

選擇題按鈕

if sender.currentTitle == rightAnswer核對答案,答對就+10分

if index < 10{} 來限定 只會有十個題目, 超過10個就會計算分

// 選擇題按鈕
@IBAction func answerClick(_ sender: UIButton) {
index = index + 1

// 如果選擇的按鈕上的文字 等於 正確答案
if sender.currentTitle == rightAnswer{
//分數加10分
score = score + 10
//顯示到Label上
scoreLabel.text = "\(score)"

}

// 在 10 題之內進行遊戲,或是結束遊戲計算總分 跑function
if index < 10{
startGame()
} else {
totalScore()
}
}

再玩一次

再玩一次 內容與 viewDidLoad 一樣

// 再玩一次
@IBAction func restartClick(_ sender: UIButton) {
restart()
}

func restart() {
score = 0
index = 0
itemNumber.text = "\(String(index + 1))"
scoreLabel.text = "0"
// 亂數排列
questionData.shuffle()
startGame()
}

viewDidLoad 設定預設值

分數預設為 0,題目預設為第1題

shuffle 出題順序亂數排列

override func viewDidLoad() {
super.viewDidLoad()

scoreLabel.text = "\(0)"
itemNumber.text = "第 \(String(index + 1)) 題"
questionData.shuffle()
startGame()
}

遊戲結束,彈跳視窗秀出結果

// 彈跳視窗訊息Function
func alertMessage(replaceTitle: String, replaceMessage: String, replaceBtnTxt: String) {
let alertController = UIAlertController (
title: replaceTitle, message: replaceMessage, preferredStyle: .alert)
let alertBtn = UIAlertAction(
title: replaceBtnTxt, style: .default, handler: {(_)in
self.restart()
})
alertController.addAction(alertBtn)
self.present(alertController, animated: true, completion: nil)
}

// 計算總分
func totalScore() {
if score >= 90 && score <= 100 {
alertMessage(replaceTitle: "總分\(score)", replaceMessage: "你就是動物達人!", replaceBtnTxt: "不不玩了實在太簡單")
}
else if score >= 60 && score <= 90 {
alertMessage(replaceTitle: "總分\(score)", replaceMessage: "有機會多認識一點動物喔!", replaceBtnTxt: "我要再玩一次")
}
else if score >= 63 && score <= 60 {
alertMessage(replaceTitle: "總分\(score)", replaceMessage: "你看顧的動物太少囉!", replaceBtnTxt: "我要再玩一次")
}
else {
alertMessage(replaceTitle: "總分\(score)", replaceMessage: "你好像沒看過動物呢", replaceBtnTxt: "我要再玩一次")
}
}

progressSlider 進度條製做

基本功能都能正常運作不出錯之後,設定 progressSlider

建立IBOutlet

@IBOutlet weak var progressSlider: UISlider!
//設slider值
func setSliderValue() {
progressSlider.maximumValue = Float(9)
progressSlider.value = Float(index)
itemNumber.text = "\(index+1)/10"
}
override func viewDidLoad() {
//略...
setSliderValue()
}
@IBAction func answerClick(_ sender: UIButton) {
//略...
setSliderValue()
}
func startGame() {
//略...
self.setSliderValue()
}

APP 除錯時光總是過得特別慢

過程中遇到二個 Bug 都是低級錯誤😅

但有時候鬼遮眼,你就是看不到擺在眼前的錯誤,這時後就是要善用 print()

或是先睡一覺,醒來就解開了(真心不騙!)

  1. 一開始只先放了四題測試,四題結束會有錯誤,所以把資料 print 出來看看錯誤在哪。
    因為條件是需要十題,我只輸入4題,所以程式會死掉
    原本想說不要打完十個再測,卻忘了必須要符合條件才會跑。
  2. 全部的按鈕選擇第四顆都沒有出現,只秀出預設值的4。把答案用print印出陣列內容對照,發現第二顆按鈕文字沒出現,,陣列內容往前移所以變成第四顆沒有動物名字出現。
    按右鍵檢查第二顆按鈕發現 Outlet 不小心拉了二個,所以會出錯😓

三種分數的畫面

--

--

Rose
彼得潘的 Swift iOS / Flutter App 開發教室

Coding & Design 一直在學習的路上,從未停止,一有空檔就會摸摸我的兔子🐰