Chapter 2: Game reset

Hi there.

I’ve just finished the 2nd chapter of the book and decided to modify behavior a bit: when a user hit the alert’s ok button to reset the game.

As far as I understand, for this, I need to mark xTarget variables with @State, also I’ve created a reset function where I reassign new values. Then I use Alert(title:message:primaryButton:) init method and in Button’s action I try to call this reset method but get an error message “Cannot use mutating member on immutable value”.

What is the working solution for this feature?

Hi Alexey! You do realise how addictive this game is :stuck_out_tongue_winking_eye: ?

You call the reset method as the dismissButton’s onTrigger completion. Here’s my version:

struct ContentView : View {
  @State var  rTarget = Double.random(in: 0 ..< 1)
  @State var  gTarget = Double.random(in: 0 ..< 1)
  @State var  bTarget = Double.random(in: 0 ..< 1)
  @State var rGuess: Double
  @State var gGuess: Double
  @State var bGuess: Double
  @State var showAlert = false
  @State var totalScore = 0

  func computeScore() -> Int {
    let rDiff = rGuess - rTarget
    let gDiff = gGuess - gTarget
    let bDiff = bGuess - bTarget
    let diff = sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff)
    let score = Int((1.0 - diff) * 100.0 + 0.5)
    totalScore += score
    return score
  }

  func setNewTarget() {
    rTarget = Double.random(in: 0 ..< 1)
    gTarget = Double.random(in: 0 ..< 1)
    bTarget = Double.random(in: 0 ..< 1)
    rGuess = 0.5
    gGuess = 0.5
    bGuess = 0.5
  }

  var body: some View {
    VStack {
      HStack {
        VStack {
          Color(red: rTarget, green: gTarget, blue: bTarget)
          Text("Match this color")
        }
        VStack {
          Color(red: rGuess, green: gGuess, blue: bGuess)
          Text("R: \(Int(rGuess * 255.0))"
            + "  G: \(Int(gGuess * 255.0))"
            + "  B: \(Int(bGuess * 255.0))")
        }
      }

      Button(action: {
        self.showAlert = true
      }) {
        Text("Hit Me!")
      }.presentation($showAlert) {
        Alert(title: Text("Your Score"),
              message: Text("\(computeScore())"),
              dismissButton: .default(Text("OK"), onTrigger: { self.setNewTarget() }
          ))
      }

      ColorSlider(value: $rGuess, textColor: .red)
      ColorSlider(value: $gGuess, textColor: .green)
      ColorSlider(value: $bGuess, textColor: .blue)

      Text("Total Score: \(totalScore)")
    }
  }
}
2 Likes

Actually, I lost my sleep yesterday because of it :slight_smile:

Neat implementation! Thank you for the help.

1 Like

For anyone reading this now, the above code did not work for me. I found the code below on Stack Overflow, which did work, using something called an Alert.Button

    Button(action: {self.showAlert.toggle()}) {
                    Text("Hit me!")
                }.alert(isPresented: $showAlert) {
                    return Alert(title: Text("Your score"),
                          message: Text(String(computeScore())),
                          dismissButton: Alert.Button.default(Text("OK"), action: {self.setNewTarget()}))
                }.padding()

thanks Steve! yes, .presentation changed to .alert(isPresented:) after I wrote that version. There’s a BullsEye version in the starter project for Chapter 5 that uses .alert(isPresented:).