Swift variable not updating depending on calling class

87 Views Asked by At

Swift newb here. The ObservableObject seems to be creating separate instances of a variable when updated. Updating the count variable from ContentView adds to a separate variable than updating the count variable from GameScene (see console log output).

I think this is because I'm creating a new instance in GameScene with PlayerStats() but haven't figured a way around.

What is the simplest way to have a single source of truth for variables - that is, both the View and the SKScene can read and update the variable(s)? Searching hasn't gotten me further than cryptic error messages (as said, newb) so thanks in advance for any info.

struct ContentView: View {
    
    @EnvironmentObject var playerstats:PlayerStats
    var scene: SKScene {
        let scene = GameScene()
        scene.size = CGSize(width: 400, height: 700)
        scene.scaleMode = .fill
        return scene
    }
    
    var body: some View {
        VStack {
            SpriteView(scene: self.scene)
                .frame(width: 400, height: 700)
                .ignoresSafeArea()
        }

        Text("Count : \(playerstats.count)")
        Button("add to count") {
            playerstats.addCount(newcount: 12)
        }.buttonStyle(.borderedProminent)
    }
}

The class

class GameScene: SKScene, SKPhysicsContactDelegate {
    let playerstats:PlayerStats = PlayerStats()// (I've tried PlayerStats?)

    override func didMove(to view: SKView) {
        self.backgroundColor = .blue
        let count = SKLabelNode(fontNamed: "Times New Roman")
        count.text = String(playerstats.count)
        count.fontSize = 65
        count.fontColor = SKColor.green
        count.position = CGPoint(x: frame.midX, y: frame.midY)
        addChild(count)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        playerstats.addCount(newcount: Int(40))
    }
    func didBegin(_ contact: SKPhysicsContact) {
        
    }
}

The observable object

class PlayerStats:ObservableObject {
    @Published var count:Int = 1
    func addCount(newcount: Int) {
        print(newcount)
        print("in add")
        count += newcount
        print(count)
    }
}

The console output

12 // from ContentView
in add
13
40 // from GameScene
in add
41
12 // from ContentView
in add
25
40 // from GameScene
in add
81
1

There are 1 best solutions below

0
openquestions On

What is working is declaring a Singleton.

class PlayerStats:ObservableObject {
    static let shared = PlayerStats()
    @Published var fuel:Int = 1
    func addFuel(newfuel: Int) {
        print("in add")
        fuel += newfuel
        print(fuel)
    }
}

and declaring

@StateObject var playerstats = PlayerStats.shared

in ContentView. And using .shared in the text

Text("Fuel : \(PlayerStats.shared.fuel)")

Big thanks to workingdogsupportUkraine in the comments.