This is a more detailed follow-up to an earlier post. As I mentioned in https://www.hackingwithswift.com/forums/swiftui/inquiry-regarding-swiftui-and-spritekit-integration/6872 , I want to update a SwiftUI View with data passed from a SpriteKit scene.
As a simple test, I have been using the demo presented in "How to integrate SpriteKit using SpriteView" (https://www.hackingwithswift.com/quick-start/swiftui/how-to-integrate-spritekit-using-spriteview).
(In the SpriteKit view, red boxes appear and drop to the floor via addChild() in touchesBegan.)
I've been trying to count the number of boxes and send this value back to SwiftUI.
The first thing I tried was to make the GameScene a subclass of ObservableObject and then use @Publish to send the value to an @ObservedObject in the ContentView. I also tried using @StateObject just for the heck of it. Neither approach worked.
I then created a BoxCounter class and gave it the following code:
import SwiftUI
class BoxCounter: ObservableObject {
var boxes : Int = 0 {
willSet {
objectWillChange.send()
self.boxes = newValue
print("New score: \(boxes)")
}
}
func add(boxes: Int) {
self.boxes += boxes
}
}
Back in GameScene, I have this:
var game = BoxCounter()
var boxes = 0 {
willSet {
objectWillChange.send()
game.add(boxes: 1)
}
}
...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
...
addChild(box)
boxes += 1
}
This does not work. Nor did it work when I first tried calling game.add(boxes: 1) elsewhere in GameScene. (The use of willSet was simply my most recent failed attempt.)
While the ContentView is not getting updated, the print("New score: (boxes)") in willSet in BoxCounter DOES give me the correct number as the boxes are created so I know that the value is being sent to BoxCounter.
I believe it is possible to send state updates manually using objectWillChange. But that is not happening here: the value of var boxes is not being updated where and when I need it to be updated, even though the newValue in the print statement is correct.
For the sake of comparison, I added a Button to ContentView to add a box manually using the same call:
Button{
game.add(boxes: 1)
} label: {
Text("Add to count")
}
This works as expected. In other words, the add(boxes) func in BoxCounter is updating var boxes, and that update is immediately reflected in ContentView.
In short, when the call is made from GameScene (i.e. from inside SpriteKit), the var doesn't update as hoped.
When the same call is made from ContentView, it behaves as expected.
At first, I thought that the instance of BoxCounter created in GameScene needed to be @ObservableObject, but that didn't work either.
Incidentally, when I tap the Button (in ContentView) to add a box manually, the print statement called in BoxCounter is reset to 1 before incrementing correctly on further taps on the "Add Button". It goes back to 1 again if I tap to create SKNodes...
I am baffled as to why the call from a View "sticks" while the one from GameScene does not.
My apologies if, by making a follow-up into a new topic, I have ignored any forum conventions, etc.
Others have asked similar questions. I hope someone can help and I look forward to sharing the solution!
Thanks.