文章摘要
GPT 4
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结

说在前面

上一篇我们学到了很多关于视图布局和样式,和像Image、Button、alert等交互元素,这一篇我们综合一下,把这些知识点融合,做一个猜旗子的demo。

直接的项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import SwiftUI

struct ContentView: View {
static let allCountries = ["Estonia","France","Germany","Ireland","Italy","Monaco","Nigeria","Poland","Spain","UK","US"]
@State private var countries = allCountries.shuffled()
@State private var correctAnswer = Int.random(in: 0...2)

@State private var showingScore = false
@State private var showingResults = false
@State private var scoreTitle = ""

@State private var score = 0
@State private var questionCounter = 1

var body: some View {
ZStack{
RadialGradient(stops: [
.init(color: Color(red:0.1,green: 0.2,blue: 0.45), location: 0.3),
.init(color: Color(red:0.76,green:0.15,blue:0.26), location: 0.3)
], center: .top, startRadius: 200, endRadius: 700)
.ignoresSafeArea()
VStack(spacing: 15){
Spacer()
Text("猜旗子")
.foregroundColor(.white)
.font(.largeTitle.weight(.semibold))
Spacer()
VStack{
VStack{
Text("选择对应的旗子🚩")
.foregroundStyle(.secondary)
.font(.subheadline.weight(.heavy))
Text(countries[correctAnswer])
.font(.largeTitle.weight(.semibold))
}
ForEach(0..<3){ number in
Button{
flagTapped(number)
}label: {
Image(countries[number])
.clipShape(Capsule())
.shadow(radius:5)
}
}
}
.frame(maxWidth: .infinity)
.padding(.vertical,20)
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 20))

Spacer()
Text("你的得分:\(score)")
.foregroundColor(.white)
.font(.title2.bold())
Spacer()
}
.padding()
}
.alert(scoreTitle,isPresented: $showingScore){
Button("继续",action: askQuestion)
} message: {
Text("你的得分是:\(score)")
}
.alert("游戏结束",isPresented: $showingResults){
Button("重新开始",action: newGame)
} message: {
Text("你的最终得分是:\(score)")
}
}

func flagTapped(_ number: Int){
if number == correctAnswer {
scoreTitle = "正确"
score += 1
} else {
scoreTitle = "错误!这个是\(countries[number])的旗子"
if(score > 0){
score -= 1
}
}
if questionCounter == Self.allCountries.count - 3 {
showingResults = true
} else {
showingScore = true
}
}

func askQuestion(){
countries.remove(at: correctAnswer)
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
questionCounter += 1
}

func newGame(){
questionCounter = 0
score = 0
countries = Self.allCountries
askQuestion()
}

}

主界面:
主界面
猜错时的提示:
猜错时的提示
答对时的提示:
答对时的提示
游戏结束时的界面:
游戏结束时的提示

讲讲思路

  1. 定义数据和状态
    • 首先,我们定义了一个静态的数组 allCountries 来存储所有的国家名称。
    • 使用 @State 包装器定义了一些关键的状态变量,如 countries (存储打乱顺序的国家名称)、correctAnswer (正确答案的索引)、showingScoreshowingResults (用于控制得分和游戏结束提示框的显示)、scoreTitle (得分提示的标题)、score (得分)和 questionCounter (问题计数器)。
  2. 构建视图布局
    • 使用 ZStack 来叠加多个视图元素,创建背景的径向渐变效果。
    • ZStack 内部,使用 VStack 进行垂直布局。
    • VStack 中,添加标题文本、显示当前要猜测的国家名称、通过 ForEach 循环创建三个按钮,每个按钮上显示一个国家的图片。
    • 还添加了显示得分的文本。
  3. 按钮交互逻辑
    • 为每个按钮定义了点击事件 flagTapped
    • 在点击事件中,根据用户选择的按钮索引与正确答案索引进行比较。如果选择正确,增加得分;如果错误,减少得分(如果得分大于 0)。
    • 根据问题计数器的值判断是否显示游戏结束或得分提示框。
  4. 游戏流程控制
    • askQuestion 函数用于在每次回答后更新问题。它移除当前正确答案所在的国家名称,重新打乱国家名称数组,重新生成正确答案索引,并增加问题计数器。
    • newGame 函数用于重置游戏状态,包括将问题计数器归零、得分归零、重新设置国家名称数组,并调用 askQuestion 开始新游戏。

知识点

  • flagTapped 中会判断是否题答完,刚开始用的 allCountries.count ,到最后答题时会崩溃,想不通,后来想到每次都会随机三个选项,每次答完减一个,最后要留够三个,不然造成数组越界。、
  • 更多地是对上一篇学到的样式和组件,进行一个总的演习,比如 alert渐变毛玻璃效果 等。