NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: Project 6, Guess the flag animation challenge

Forums > SwiftUI

I am having a lot of trouble being able to solve the opacity challenge. In the code I currently have, the opacity is applied from the beginning (making spoilers of the result lol).

I can't get the ternary conditional to happen after the user chooses the right option. Any help? Thank!!!

//
//  ContentView.swift
//  GuessTheFlag
//
//  Created by Lucas on 10/11/21.
//

import SwiftUI

extension Image: ViewModifier {
    func flagImage() -> some View {
        self
            .clipShape(Capsule())
            .shadow(radius: 10)
    }
}

struct ContentView: View {
    @State private var showingScore = false
    @State private var scoreTitle = ""
    @State private var score = 0

    @State private var endGame = false
    @State private var questionAsked = 0

    @State private var finishTitle = ""

    @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)

    //Animation

    @State private var animationAmount = 0.0
    @State private var opacityAmount = 0.5

    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: 800)
                .ignoresSafeArea()

            VStack {
                Spacer()

                Text("Guess the Flag")
                    .font(.largeTitle.bold())
                    .foregroundColor(.white)

                VStack (spacing: 15){
                    VStack {
                        Text("Tap the flag of")
                            .font(.subheadline.weight(.heavy))
                            .foregroundStyle(.secondary)
                        Text(countries[correctAnswer])
                            .font(.largeTitle.weight(.semibold))
                    }

                    ForEach(0..<3) { number in
                        Button {
                            flagTapped(number)
                            withAnimation {
                                animationAmount += 360
                                opacityAmount = 1.0
                            }
                        } label: {
                            Image(countries[number])
                                .flagImage()
                        }
                        .rotation3DEffect(.degrees((number == correctAnswer) ? animationAmount : 0.0), axis: (x: 0, y: 1, z: 0))
                        .opacity((number == correctAnswer) ? opacityAmount : 0.5)
                    }
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 20)
                .background(.ultraThinMaterial)
                .clipShape(RoundedRectangle(cornerRadius: 40))

                Spacer()
                Spacer()

//                Text("Question: \(questionAsked)") // Just to see the number
                Text("Score: \(score) ")
                    .foregroundColor(.white)
                    .font(.title.bold())
                Spacer()
            }
            .padding()
        }
        .alert(scoreTitle, isPresented: $showingScore) {
            Button("Continue", action: askQuestion)
        } message: {
            Text("Your score is \(score)")
        }
        .alert(finishTitle, isPresented: $endGame) {
            Button("Start again!", action: resetGame) // Change action
        } message: {
            Text("Great! Your final score is \(score)")
        }
    }

    func flagTapped(_ number: Int) {
            if number == correctAnswer {
                scoreTitle = "Correct!"
                score += 1
            } else {
                scoreTitle = "Wrong! That's the flag of \(countries[number])"
            }
            showingScore = true
    }

     func askQuestion() {
         if questionAsked == 9 {
             finishTitle = "Game Finish"
             endGame = true
         } else {
             countries.shuffle()
             correctAnswer = Int.random(in: 0...2)
             questionAsked += 1
         }
    }

    func resetGame() {
        score = 0
        questionAsked = 0
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1      

The ternary is working in terms of the opacity, however you need to reset the opacity in preparation for the next flag guess. I have used your code as the basis for this reply, so hopefully it is easier for you to understand the differences.

func askQuestion() {
     opacityAmount = 0.5         // reset opacity for the next guess or when the game finishes
     if questionAsked == 9 {
         finishTitle = "Game Finish"
         endGame = true
     } else {
         countries.shuffle()
         correctAnswer = Int.random(in: 0...2)
         questionAsked += 1
     }
 }

Also you don't need the double spacer, you can specify the minimum amount of spacing needed (to prevent items overlapping)

//        Spacer()
        Spacer(minLength: 20)   // this will use more spacing if availabe, but the least amount will be 20

After resetting the game, you need to randomize the next flag selection in the new game.

func resetGame() {
    score = 0
    questionAsked = 0
    askQuestion()           // this will also select a random flag for the new game.
}

Finally need to add Monaco to the list of countries, as the flag image is available, but never selected as one of the three random flags. Paul missed this in the code and video.

@State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled()

Hope this helps.

1      

It has worked and I have also been able to improve my code thanks to your suggestions. Thank you very much for your very complete answer!

1      

Hacking with Swift is sponsored by MadMachine

SPONSORED Want to try Swift on microcontrollers? MadMachine provides ways to interact with the physical world in a Swift way. Join us and have fun!

Get it now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.