#4 選擇題App|卡通人物猜猜樂

前陣子因朋友分享台灣本色檢定考測驗,做完後覺得很難但也很有趣,因此給了我靈感來做這次的選擇題App,大家一起來挑戰看看吧!

學習目標

  1. 製作選擇題App,每題有四個選項。
  2. 答對一題加10分。
  3. 畫面上顯示目前題目是第幾題。
  4. 自訂選擇題的資料型別。
  5. 題庫有 n 題,隨機出其中的 10 題,每次玩的時候題目順序都不一樣。( n > 10 )
  6. 使用 UIAlertController 顯示 alert。

StoryBoard架構

  • 第一頁(Home)ViewCountroller:首頁,點選Go按鈕進入第二頁。
  • 第二頁(Question)ViewController:題目頁面,功能應用如下:
    1) 題目共有20題,每一次會從中隨機出10題
    2) 答對一題可得10分
    3) 上方Slider與Label會顯示目前題數進度 (Slider需取消勾選User Interaction Enabled,才會只有進度功能,無法滑動)
    4) 若答對,button會呈現橘色底 ; 答錯會呈現灰底灰字,並以橘色底顯示正確答案
    5) 不論答對與否,皆會呈現正確角色圖片
    6) 按下一題才能進入下一題
    7) alert訊息視窗顯示總分 & 是否再玩一次/結束

程式撰寫

自訂型別(Cartoon)

import Foundation

struct Cartoon {
var questionPic1: String
var questionPic2: String
var questionPic3: String
var questionPic4: String
var option: [String]
var answer: String
var characterPic: String
}

第一頁 Country View Controller

  • Go按鈕拉Segue到第二頁Question View Controller
    Kind選「Present Modally」 ; Presentation選「Full Screen」

第二頁 Question View Controller

  1. @IBOutlet
  @IBOutlet weak var numberSlider: UISlider!
@IBOutlet weak var numberLabel: UILabel!
@IBOutlet weak var scoreLabel: UILabel!
@IBOutlet var questionImageView1: UIImageView!
@IBOutlet weak var questionImageView2: UIImageView!
@IBOutlet weak var questionImageView3: UIImageView!
@IBOutlet weak var questionImageView4: UIImageView!
@IBOutlet var optionButton: [UIButton]!
@IBOutlet weak var characterImageView: UIImageView!
@IBOutlet weak var nextButton: UIButton!

2. 建立array存放資料

//宣告儲存Cartoon屬性的questions
var questions =
[Cartoon(questionPic1: "Anya_Color1", questionPic2: "Anya_Color2", questionPic3: "Anya_Color3", questionPic4: "Anya_Color4", option: ["佩佩豬", "安妮亞", "胖丁", "卡比獸"], answer: "安妮亞", characterPic: "Anya"),
Cartoon(questionPic1: "Baikinman_Color1", questionPic2: "Baikinman_Color2", questionPic3: "Baikinman_Color3", questionPic4: "white", option: ["灶門禰豆子", "天線寶寶-丁丁", "耿鬼", "細菌人"], answer: "細菌人", characterPic: "Baikinman"),
Cartoon(questionPic1: "Charles_Color1", questionPic2: "Charles_Color2", questionPic3: "Charles_Color3", questionPic4: "black", option: ["查理布朗", "皮卡丘", "海綿寶寶", "小熊維尼"], answer: "查理布朗", characterPic: "Charles"),
Cartoon(questionPic1: "Conan_Color1", questionPic2: "Conan_Color2", questionPic3: "Conan_Color3", questionPic4: "white", option: ["哆啦A夢", "柯南", "唐老鴨", "白雪公主"], answer: "柯南", characterPic: "Conan"),
Cartoon(questionPic1: "Crayon_Color1", questionPic2: "Crayon_Color2", questionPic3: "Crayon_Color3", questionPic4: "black", option: ["小小兵", "老皮", "蠟筆小新", "布丁狗"], answer: "蠟筆小新", characterPic: "Crayon"),
Cartoon(questionPic1: "Doraemon_Color1", questionPic2: "Doraemon_Color2", questionPic3: "Crayon_Color1", questionPic4: "white", option: ["辛普森", "威力", "藍色小精靈", "哆啦A夢"], answer: "哆啦A夢", characterPic: "Doraemon"),
Cartoon(questionPic1: "Doremi_Color1", questionPic2: "Doremi_Color2", questionPic3: "Doremi_Color3", questionPic4: "Anya_Color1", option: ["小魔女DoReMi", "頑皮豹", "熊抱哥", "小豬"], answer: "小魔女DoReMi", characterPic: "DoReMi"),
Cartoon(questionPic1: "Hattori_Color1", questionPic2: "Charles_Color1", questionPic3: "Crayon_Color1", questionPic4: "white", option: ["音速小子", "伊布", "忍者哈特利", "水箭龜"], answer: "忍者哈特利", characterPic: "Hattori"),
Cartoon(questionPic1: "Jerry_Color1", questionPic2: "Jerry_Color2", questionPic3: "Jerry_Color3", questionPic4: "black", option: ["咖哩麵包超人", "傑利鼠", "布丁狗", "章魚哥"], answer: "傑利鼠", characterPic: "Jerry"),
Cartoon(questionPic1: "Kenny_Color1", questionPic2: "Kenny_Color2", questionPic3: "Crayon_Color3", questionPic4: "black", option: ["肯尼", "噴火龍", "加菲貓", "小病毒"], answer: "肯尼", characterPic: "Kenny"),
Cartoon(questionPic1: "Maruko_Color1", questionPic2: "white", questionPic3: "Jerry_Color4", questionPic4: "black", option: ["小紅帽", "小不點", "佩佩豬", "櫻桃小丸子"], answer: "櫻桃小丸子", characterPic: "Maruko"),
Cartoon(questionPic1: "Naruto_Color1", questionPic2: "Naruto_Color2", questionPic3: "Naruto_Color3", questionPic4: "Naruto_Color4", option: ["漩渦鳴人", "麵包超人", "小火龍", "咖哩麵包超人" ], answer: "漩渦鳴人", characterPic: "Naruto"),
Cartoon(questionPic1: "Patrick_Color1", questionPic2: "Patrick_Color2", questionPic3: "Patrick_Color3", questionPic4: "white", option: ["妙蛙種子", "派大星", "天線寶寶-丁丁", "阿拉蕾"], answer: "派大星", characterPic: "Patrick"),
Cartoon(questionPic1: "Pig_Color1", questionPic2: "Virus_Color1", questionPic3: "black", questionPic4: "white", option: ["佩佩豬", "吐司麵包超人", "史奴比", "小豬"], answer: "佩佩豬", characterPic: "Pig"),
Cartoon(questionPic1: "Pikachu_Color1", questionPic2: "Pikachu_Color2", questionPic3: "Crayon_Color1", questionPic4: "black", option: ["蛋黃哥", "可達鴨", "皮卡丘", "小拉達"], answer: "皮卡丘", characterPic: "Pikachu"),
Cartoon(questionPic1: "Police_Color1", questionPic2: "Charles_Color2", questionPic3: "white", questionPic4: "black", option: ["兩津勘吉", "口呆花", "小小兵", "酷企鵝"], answer: "兩津勘吉", characterPic: "Police"),
Cartoon(questionPic1: "Sponge_Color1", questionPic2: "Sponge_Color2", questionPic3: "Sponge_Color3", questionPic4: "Crayon_Color1", option: ["跳跳虎", "米老鼠", "Hello Kitty", "海綿寶寶"], answer: "海綿寶寶", characterPic: "SpongeBob"),
Cartoon(questionPic1: "Stitch_Color1", questionPic2: "Stitch_Color2", questionPic3: "Stitch_Color3", questionPic4: "Stitch_Color4", option: ["鬼斯", "柴郡貓", "史迪奇", "烏蘇拉"], answer: "史迪奇", characterPic: "Stitch"),
Cartoon(questionPic1: "Tom_Color1", questionPic2: "Tom_Color2", questionPic3: "Tom_Color3", questionPic4: "white", option: ["湯姆貓", "音速小子", "布魯托", "龍貓"], answer: "湯姆貓", characterPic: "Tom"),
Cartoon(questionPic1: "Virus_Color1", questionPic2: "Virus_Color2", questionPic3: "Kenny_Color1", questionPic4: "white", option: ["跳跳虎", "胖虎", "加菲貓", "小病毒"], answer: "小病毒", characterPic: "Virus")
]

3. 宣告題數、分數、答案、選項button狀態之變數

    var index = 0             //宣告index儲存目前題數
var score = 0 //宣告答題總分變數
var answer = String() //宣告答案變數
var buttonEnabled = true //button的狀態

4. 建立與畫面有關的函式,後面可以不用一直重複寫

func updateView() {
//slider顯示目前題數
numberSlider.value = Float(index + 1)
//label顯示目前題數
numberLabel.text = "\(index + 1) / 10"
//分數計算
scoreLabel.text = "\(score)"
//讀取每個題目的圖片
questionImageView1.image = UIImage(named: "\(questions[index].questionPic1)")
questionImageView2.image = UIImage(named: "\(questions[index].questionPic2)")
questionImageView3.image = UIImage(named: "\(questions[index].questionPic3)")
questionImageView4.image = UIImage(named: "\(questions[index].questionPic4)")
//讀取答案
answer = questions[index].answer
//正確圖片出來前的預設頭像
characterImageView.image = UIImage(systemName: "questionmark.app")
//設定option button顯示的title
for i in 0...3 {
//檢查i
if i >= questions.startIndex && i < questions.endIndex {
print(questions[i])
}
optionButton[i].setTitle(questions[index].option[i], for: .normal)

}
}

5. 進入畫面時:
→使用 .shuffle() 更改題目與選項順序
→更改slider thumb的圖案
→設定四個questionImageView的邊框顏色及寬度

override func viewDidLoad() {
super.viewDidLoad()

//每次打開app時會更改題目順序
questions.shuffle()
//更改option順序
questions[index].option.shuffle()
updateView()
//更改slider thumb image
let image = UIImage(named: "footprints")
numberSlider.setThumbImage(image, for: .normal)
//設定questionImageView的邊框顏色
questionImageView1.layer.borderColor = CGColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
questionImageView1.layer.borderWidth = 2
questionImageView2.layer.borderColor = CGColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
questionImageView2.layer.borderWidth = 2
questionImageView3.layer.borderColor = CGColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
questionImageView3.layer.borderWidth = 2
questionImageView4.layer.borderColor = CGColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.5)
questionImageView4.layer.borderWidth = 2
}

6. 四個選項button: 只能點選一次
→若答對:button會變橘色底,分數加10分,並顯示正確角色圖片
→若答錯:button會變灰底灰字,並且會以橘色底顯示正確答案,也會顯示正確角色圖片
→做完十題:計算分數

 //選擇答案
@IBAction func selectAnswer(_ sender: UIButton) {
if buttonEnabled {
buttonEnabled = false
//如果選到正確答案
if sender.titleLabel?.text == questions[index].answer {
sender.tintColor = .orange
score += 10
scoreLabel.text = "\(score)"
characterImageView.image = UIImage(named: "\(questions[index].characterPic)")
} else {
sender.tintColor = .lightGray
sender.setTitleColor(.gray, for: .normal)
characterImageView.image = UIImage(named: "\(questions[index].characterPic)")
//找出正確答案,並呈現橘色
for choicebtn in 0...optionButton.count-1 {
if optionButton[choicebtn].titleLabel?.text == questions[index].answer {
optionButton[choicebtn].tintColor = .orange
}
}
}
}
//做答完第十題則計算分數
if index == 9 {
caculateScore()
}
}

7. 下一題

//下一題
@IBAction func nextQuestion(_ sender: UIButton) {
index += 1
updateView()

//當回答到第10題,但沒有選擇答案時,按下一題會直接計算分數
if index == 10 {
caculateScore()
}

//option button和字體的顏色改回原本的樣子
for i in 0...3 {
optionButton[i].tintColor = .systemTeal
optionButton[i].setTitleColor(.white, for: .normal)
}

buttonEnabled = true
}

8. 再玩一次
題數需從0開始,分數要歸0,選項button狀態為可點選

//再玩一次
func playAgain() {
index = 0
score = 0
viewDidLoad()

for i in 0...3 {
optionButton[i].tintColor = .systemTeal
optionButton[i].setTitleColor(.white, for: .normal)
}

buttonEnabled = true
}

9. 做答完10題後,以UIAlertController產生訊息視窗,並顯示分數,可點選再玩一次或是結束遊戲。

→ UIAlertController產生訊息視窗
→ UIAlertAction產生視窗上的按鈕(確認、取消)
→ addAction將按鈕加入訊息視窗中
→ present切換頁面來顯示訊息視窗

訊息視窗依總分區分為四種不同的訊息,但都可以選擇再玩一次或是結束。

//第十題作答完成時,計算分數
func caculateScore() {
if score >= 80 {
let alertController = UIAlertController(title: "總分\(score)分", message: "你是卡通神人!!!", preferredStyle: .alert)
//確認按鈕
let okAction = UIAlertAction(title: "再玩一次", style: .default) { _
in
self.playAgain()
}
//取消按鈕
let cancelAction = UIAlertAction(title: "結束", style: .destructive) {
_ in
self.dismiss(animated: true)
}
//將按鈕加入訊息視窗
alertController.addAction(okAction)
alertController.addAction(cancelAction)
//顯示訊息視窗
present(alertController, animated: true, completion: nil)
} else if score >= 60 && score < 80 {
let alertController2 = UIAlertController(title: "總分\(score)分", message: "哇嗚~你好厲害!", preferredStyle: .alert)
//確認按鈕
let okAction = UIAlertAction(title: "再玩一次", style: .default) { _
in
self.playAgain()
}
//取消按鈕
let cancelAction = UIAlertAction(title: "結束", style: .destructive) {
_ in
self.dismiss(animated: true)
}
//將按鈕加入訊息視窗
alertController2.addAction(okAction)
alertController2.addAction(cancelAction)
//顯示訊息視窗
present(alertController2, animated: true, completion: nil)
} else if score >= 40 && score < 60 {
let alertController3 = UIAlertController(title: "總分\(score)分", message: "加油加油!", preferredStyle: .alert)
//確認按鈕
let okAction = UIAlertAction(title: "再玩一次", style: .default) { _
in
self.playAgain()
}
//取消按鈕
let cancelAction = UIAlertAction(title: "結束", style: .destructive) {
_ in
self.dismiss(animated: true)
}
//將按鈕加入訊息視窗
alertController3.addAction(okAction)
alertController3.addAction(cancelAction)
//顯示訊息視窗
present(alertController3, animated: true, completion: nil)
} else {
let alertController4 = UIAlertController(title: "總分\(score)分", message: "可以多看一些卡通喔!", preferredStyle: .alert)
//確認按鈕
let okAction = UIAlertAction(title: "再玩一次", style: .default) { _
in
self.playAgain()
}
//取消按鈕
let cancelAction = UIAlertAction(title: "結束", style: .destructive) {
_ in
self.dismiss(animated: true)
}
//將按鈕加入訊息視窗
alertController4.addAction(okAction)
alertController4.addAction(cancelAction)
//顯示訊息視窗
present(alertController4, animated: true, completion: nil)
}
}

--

--