NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

Follow Up to Inquiry on SpriteKit and SwiftUI integration

Forums > SwiftUI

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.

   

Replying to my own question here... A response to a similar query on StackOverflow suggested that the problem was caused by the creation of a new instance of BoxCounter() in Game scene. The correction involved changing the existing line to:

var game: BoxCounter?

Then calling the add function like this:

game?.add(box: boxes)

And finally, I needed to add this to ContentView after creating the scene:

scene.game = game

The ContentView is now updating with data passed from the GameScene. I hope this helps anyone else who has had similar problems.

   

Hacking with Swift is sponsored by Instabug

SPONSORED Catch bugs as soon as they happen and know exactly why a crash occurred. Instabug's SDK grabs all the logs they need to fix bugs, crashes and performance issues in minutes instead of days. Get screenshots, device details, network logs, repro steps, and tons of other critical insights needed to resolve issues and prioritize product backlogs straight from your dashboard. It only takes a minute to integrate!

Get started now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.