Hi everyone,
I am following 100 days of SwiftUI schedule. I have finished day 34 and my code run without error. However to be honest I am not very happy with my code;
- I used "newArr" variable array to keep track if the button is tapped or not which I beleive there is more effective solution for that purpose.
- I could not find a way to alert message to appear below flag images.
- Game is on as round < 5. I used if statement for this purpose but I think using while loop is better for this purpose. However I am not allowed to use while inside struct. Is there any specific reason ?
Please see my code below;
import SwiftUI
struct Title: ViewModifier {
func body(content: Content) -> some View {
content
// .font(.largeTitle.bold())
.font(.system(size: 36.0).bold())
.foregroundColor(.white)
}
}
extension View {
func titleStyle() -> some View {
modifier(Title())
}
}
struct FlagImage: View {
var text: String
var rotateAmount: Double
var opacityAmount: Double
var scaleAmount: Double
var body: some View {
Image(text)
.renderingMode(.original)
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.black, lineWidth: 2))
.shadow(radius: 5)
.opacity(opacityAmount)
.scaleEffect(scaleAmount)
.rotation3DEffect(.degrees(Double(rotateAmount)),
axis: (x: 0.0, y: 1.0, z: 0.0))
}
}
struct ContentView: View {
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()
@State private var correctAnswer = Int.random(in:0...2)
@State private var score = 0
@State private var round = 0
@State private var newArr = [false, false, false] // Used to check if the button is tapped. true if button is tapped.
@State private var rotateAmount = 0.0
@State private var opacityAmount = 1.0
@State private var scaleAmount = 1.0
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 {
Text("Guess the Flag")
.titleStyle()
if round<5 {
VStack(spacing: 15) {
VStack {
Text ("Tap the flag of")
.foregroundStyle(.secondary)
.font(.subheadline.weight(.heavy))
Text(countries[correctAnswer])
.font(.largeTitle.weight(.semibold))
}
ForEach(0..<3) { number in
Button {
flagTapped(number)
newArr[number] = true
withAnimation(.easeOut(duration: 1)) {
rotateAmount += 360
}
withAnimation() {
opacityAmount -= 0.75
scaleAmount -= 0.5
}
} label: {
FlagImage(text: countries[number],
rotateAmount: (newArr[number] ? rotateAmount : 0),
opacityAmount: (!newArr[number] ? opacityAmount : 1),
scaleAmount: (!newArr[number] ? scaleAmount : 1)
)
}
}
}
.frame(maxWidth: .infinity)
.padding(.vertical, 20)
.background(.thinMaterial)
.clipShape(RoundedRectangle(cornerRadius: 20))
Spacer()
Spacer()
Text("Score: \(score)")
.foregroundColor(.white)
.font(.title.bold())
Spacer()
} else {
VStack(spacing: 15) {
VStack {
Spacer()
Text ("Game is over. Your score is \(score)/8")
.foregroundStyle(.secondary)
.font(.largeTitle.weight(.semibold))
Spacer()
}
Button {
restart()
} label: {
Text("Click to restart the game!")
.padding()
.foregroundColor(.white)
}
.buttonStyle(.borderedProminent)
.tint(.mint)
}
}
}
.padding()
}
.alert(scoreTitle, isPresented: $showingScore) {
Button("Continue", action: askQuestion)
} message: {
Text("Your score is \(score)")
}
}
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else {
scoreTitle = "Wrong. That is the flag of \(countries[number])"
}
round += 1
showingScore = true
}
func askQuestion() {
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
newArr = [false, false, false]
opacityAmount = 1.0
rotateAmount = 0.0
scaleAmount = 1.0
}
func restart () {
score = 0
round = 0
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Thanks in advance.