In the second project of the course we’re shown how to create a completely custom-looking UI with the built-in functionality of SwiftUI.
Over the course of this 3 day project we’re introduced to VStack
, HStack
and ZStack
as well as Color
, different kinds of gradient, frames, buttons and how to show alerts – so quite a lot really!
This is all pulled together into a game where the user is shown a country name and three flags then needs to tap the correct one. Although it is a pretty simple game, it’s still engaging enough. It’s surprising just how much you can achieve with very little code.
Challenge
After completing the project we have 3 challenges to complete to extend the game.
Scoring
First we add score tracking to the app. This is achieved with a new @State
property named score
which is initially set to 0 and then incremented within the flagTapped
method if number == correctAnswer
.
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else { ...
There’s also a couple of places in the code that Paul has us write Score: ???
. We replace ???
with \(score)
to correctly interpolate the actual score into these labels.
Wrong answer message
We’re asked to enhance the message displayed when the user selects the wrong flag to inform them of the correct answer. This is a simple one-line change in the flagTapped
method where the scoreTitle
text is set where we interpolate the name of the flag the user tapped.
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else {
scoreTitle = "Wrong! That's the flag of \(countries[number])"
} ...
Question limit and final score
Our last challenge is to limit the quiz to 8 questions and then display a final score to the user.
We’ll need another couple of @State
properties for this. First is questionsAsked
which is an Int
initialised to 0 that we’ll use to count how many questions are asked. We’ll also need a Bool
called endOfGame
, set to false
, which we’ll use to trigger the final alert message. Finally, I need a new method called resetGame
which puts everything back to their initial state and randomises the countries
array and correctAnswer
again for a new game.
At the end of the outer VStack
I add an alert trigger for endOfGame
that shows the final score and calls resetGame
.
.alert("Game over", isPresented: $endOfGame) {
Button("Start again", action: resetGame)
} message: {
Text("Your final score is \(score)!")
}
The flagTapped
method is amended to increment questionsAsked
each time it’s called.
func flagTapped(_ number: Int) {
if number == correctAnswer {
scoreTitle = "Correct"
score += 1
} else {
scoreTitle = "Wrong! That's the flag of \(countries[number])"
}
showingScore = true
questionsAsked += 1
}
I also need to amend the askQuestion
method to check the value of questionsAsked
and then either trigger the endOfGame
alert or ask another question depending on whether we’ve asked the user 8 questions or not.
func askQuestion() {
if questionsAsked == 8 {
endOfGame = true
} else {
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
}
Last, but not least, is my resetGame
method.
func resetGame() {
score = 0
questionsAsked = 0
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
Phew! That was quite a lot of change but now we have a better gaming experience with scoring, a game over screen and a reset.
Complete solution
