How to show random array's items only once in SwiftUI?

Viewed 90

I'm trying to recreate a popular game: Heads up, basically the user has to try to guess the name putting the phone on his head, with friends' suggestions...if he raises the head he skips the word, if he lowers the head it means he guessed the name and he earns a point. He has limited time. I need that every time the user raises/lowers his head, the array's name changes, and each name must appear only once. Any suggestions?

This is my code:

import SwiftUI
import CoreMotion

struct ContentView: View {
    
    let motionManager = CMMotionManager()
    let queue = OperationQueue()
    @State private var roll = Double.zero
    
    @State private var people = ["John", "Marcus", "Steve", "Eric", "Philip"].shuffled()
    @State private var randomPerson = Int.random(in: 0...4)
    
    let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
    @State private var timeRemaining = 10
    @State private var score = 0
    
    var body: some View {
        NavigationView {
            ZStack {
                //Show a red background and "SKIP" if the user raises head
                if roll < 1 {
                    Color.red
                        .ignoresSafeArea()
                    
                    Text("SKIP")
                        .font(.largeTitle)
                        .bold()
                        .foregroundColor(.white)
                } else if roll > 2.1 {
                //Show a green background and "CORRECT" if user lowers head
                    Color.green
                        .ignoresSafeArea()
                    
                    Text("CORRECT")
                        .font(.largeTitle)
                        .bold()
                        .foregroundColor(.white)
                        .onAppear {
                            score += 1
                        }
                } else {
                //Otherwise show a cyan back with array's name
                    Color.cyan
                        .ignoresSafeArea()
                    
                    Text(people[randomPerson])
                        .font(.largeTitle)
                        .bold()
                        .foregroundColor(.white)
                }
                
                Text("\(timeRemaining)")
                    .font(.system(size: 39))
                    .padding(.bottom, 200)
                    .onReceive(timer) { _ in
                        if timeRemaining > 0 {
                            timeRemaining -= 1
                        }
                    }
                
                Text("Score: \(score)")
                    .font(.largeTitle)
                    .bold()
                    .foregroundColor(.white)
                    .padding(.top, 200)
            }
            .onAppear {
                //Detect device motion
                self.motionManager.startDeviceMotionUpdates(to: self.queue) { (data: CMDeviceMotion?, error: Error?) in
                    guard let data = data else {
                        print("Error: \(error!)")
                        return
                    }
                    let attitude: CMAttitude = data.attitude
                    
                    DispatchQueue.main.async {
                        self.roll = attitude.roll
                    }
                }
            }
        }
        .navigationViewStyle(.stack)
    }
}
1 Answers

You can do like this:

  1. a state variable for current selected person

@State private var currerntPerson : String = ""

  1. a function to get random person

getRandomPerson()

  1. change TextView show selected person name:
Text(currerntPerson)
   .font(.largeTitle)
   .bold()
   .foregroundColor(.white)
   .onAppear {
        getRandomPerson()
   }

==== All code here:

let motionManager = CMMotionManager()
let queue = OperationQueue()
@State private var roll = Double.zero

@State private var people = ["John", "Marcus", "Steve", "Eric", "Philip"].shuffled()
@State private var randomPerson = Int.random(in: 0...4)

let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var timeRemaining = 10
@State private var score = 0
@State private var currerntPerson : String = ""

var body: some View {
    NavigationView {
        ZStack {
            //Show a red background and "SKIP" if the user raises head
            if roll < 1 {
                Color.red
                    .ignoresSafeArea()
                
                Text("SKIP")
                    .font(.largeTitle)
                    .bold()
                    .foregroundColor(.white)
            } else if roll > 2.1 {
                //Show a green background and "CORRECT" if user lowers head
                Color.green
                    .ignoresSafeArea()
                
                Text("CORRECT")
                    .font(.largeTitle)
                    .bold()
                    .foregroundColor(.white)
                    .onAppear {
                        score += 1
                    }
            } else {
                //Otherwise show a cyan back with array's name
                Color.cyan
                    .ignoresSafeArea()
                
                Text(currerntPerson)
                    .font(.largeTitle)
                    .bold()
                    .foregroundColor(.white)
                    .onAppear {
                        getRandomPerson()
                    }
            }
            
            Text("\(timeRemaining)")
                .font(.system(size: 39))
                .padding(.bottom, 200)
                .onReceive(timer) { _ in
                    if timeRemaining > 0 {
                        timeRemaining -= 1
                    }
                }
            
            Text("Score: \(score)")
                .font(.largeTitle)
                .bold()
                .foregroundColor(.white)
                .padding(.top, 200)
        }
        .onAppear {
            //Detect device motion
            self.motionManager.startDeviceMotionUpdates(to: self.queue) { (data: CMDeviceMotion?, error: Error?) in
                guard let data = data else {
                    print("Error: \(error!)")
                    return
                }
                let attitude: CMAttitude = data.attitude
                
                DispatchQueue.main.async {
                    self.roll = attitude.roll
                }
            }
        }
    }
    .navigationViewStyle(.stack)
}

func getRandomPerson() {
    if people.count > 0 {
        let index = Int.random(in: 0..<people.count)
        currerntPerson = people[index]
        people.remove(at: index)
    }
}
Related