import SwiftUI
struct characterDetail: View {
@AppStorage("USER_HEALTH") var userHealth = 100
@AppStorage("GOLD") var gold = 100
@AppStorage("USER_PRESTIGE") var userPrestige = 0
@AppStorage("USER_GLORY") var userGlory = 0
@AppStorage("USER_ARMOR") var userArmor = 0
@AppStorage("USER_SPEED") var userSpeed = 0
@AppStorage("USER_DAMAGE") var userDamage = 0
var body: some View {
VStack{
ZStack{
Rectangle()
.fill(.gray.opacity(0.1))
.cornerRadius(20)
HStack{
Image("character")
.resizable()
.frame(width: 100, height: 100)
VStack(alignment: .leading) {
Text("Character Stats")
.bold()
Text("Health: \(userHealth)")
Text("Gold: \(gold)")
Text("Prestige: \(userPrestige)")
Text("Glory: \(userGlory)")
}
.offset(x:0, y:-10)
}
}
}
.frame(width: 350, height: 200)
}
}
Every time I finish the missions user health goes down. When its come to 0 I wanna reset those all variables. Or the app get back to first shape like first time you build.
A restart function for game I tried to do someone but I couldn't. I hope I will find what I am looking for. Thank you for your help.
import SwiftUI
struct firstMissionButton: View {
@AppStorage("USER_HEALTH") var userHealth = 100
@State private var countDownTimer = 5
@State private var timerRuning = false
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
VStack{
Button(action:{
timerRuning = true
userHealth -= 20
} ){
Text("GO! Mission Time: \(countDownTimer) sec.")
}.onReceive(timer){_ in
if countDownTimer > 0 && timerRuning {
countDownTimer -= 1
}
else {
timerRuning = false
countDownTimer = 5
}
}.disabled(timerRuning)
}
}
}
struct firstMissionButton_Previews: PreviewProvider {
static var previews: some View {
firstMissionButton()
}
}
this is the place I change the userHealth.
CodePudding user response:
I would recommend using an enum for the keys of your @AppStorage
. This would also provide some sort of safety regarding typos in the String
declaration in @Appstorage
.
enum UserKeys: String, CaseIterable{
case health = "USER_HEALTH"
case gold = "GOLD"
case prestige = "USER_PRESTIGE"
case glory = "USER_GLORY"
case armor = "USER_ARMOR"
case speed = "USER_SPEED"
case damage = "USER_DAMAGE"
}
Then create an extension for UserDefaults
that removes exactly these keys:
extension UserDefaults {
func resetUser(){
UserKeys.allCases.forEach{
removeObject(forKey: $0.rawValue)
}
}
}
Usage:
@AppStorage(UserKeys.health.rawValue) var userHealth = 100
@AppStorage(UserKeys.gold.rawValue) var gold = 100
@AppStorage(UserKeys.prestige.rawValue) var userPrestige = 0
@AppStorage(UserKeys.glory.rawValue) var userGlory = 0
@AppStorage(UserKeys.armor.rawValue) var userArmor = 0
@AppStorage(UserKeys.speed.rawValue) var userSpeed = 0
@AppStorage(UserKeys.damage.rawValue) var userDamage = 0
and the function to remove would be:
UserDefaults.standard.resetUser()
It would be best to check for userHealth == 0
and call the removeUser
function at the place where you decrement it. But that is not shown in your code example.
Edit:
It should be something like this but without knowing the rest of your logic it is hard to say if the timer should execute after userHealth is below or at zero:
Button(action:{
userHealth -= 20
if userHealth <= 0{
UserDefaults.standard.resetUser()
return
}
timerRuning = true
}
Remarks:
This is just a hunch and not related to the question, but I think it would be best to move the code for manipulating an checking the health property to the else
clause of the timer fired function.
CodePudding user response:
I think it’s already posted here, but try the following function:
extension UserDefaults {
func resetDefaults() {
let dictionary = self.dictionaryRepresentation()
dictionary.keys.forEach({self.removeObject(forKey: $0})
}
}