How do you handle onChange() of @EnvironmentObject in an SKScene, and not break the scene rendering?

650 Views Asked by At

In the test code below the blue ellipse is drawn, but the red ellipse is not drawn. Is there a way to handle the onChange and call a drawing function in a SpriteKit scene? (The print statement inside handleDataChange() does print to the console.)

The gameEnvData is being changed in a separate scene.

import SwiftUI
import SpriteKit

struct NextPieceView: View {
    @EnvironmentObject var gameEnvData: GameData
    
    var scene: NextPieceScene {
        let scene = NextPieceScene()
        scene.size = CGSize(width: 200, height: 100)
        scene.gameData = gameEnvData
        return scene
    }
    var body: some View {
        SpriteView(scene: scene)
        .onChange(of: gameEnvData.pieceCount, perform: { _ in
            scene.handleDataChange()
        })
    }
}
import SpriteKit
class NextPieceScene: SKScene {
    var gameData: GameData = GameData()
    override func didMove(to view: SKView) {
        drawTestShape(position: CGPoint(x: 25, y: 50), color: .blue) // this works
    }
    
    func handleDataChange() {
        print("handleDataChange called")
        drawTestShape(position: CGPoint(x: 75, y: 50), color: .red) // does not draw
    }
    
    func drawTestShape(position: CGPoint, color: UIColor) {
        let shapeNode = SKShapeNode(ellipseOf: CGSize(width: 40, height: 40))
        shapeNode.fillColor = color
        shapeNode.position = position
        addChild(shapeNode)
    }
}
1

There are 1 best solutions below

0
Robert22 On

Fixes:

  1. Used the @State wrapper when declaring the scene
  2. The scene could no longer be a computed property, due to wrapper
  3. Now passing the @EO gameEnvData in via the onChange handler
struct NextPieceView: View {
    @EnvironmentObject var gameEnvData: GameData
    
    @State var scene: NextPieceScene = NextPieceScene(
        size: CGSize(width: 200, height: 100))
    
    var body: some View {
        SpriteView(scene: scene)
        .onChange(of: gameEnvData.pieceCount, perform: { _ in
            scene.handleDataChange(gameEnvData: gameEnvData) })
    }
}