SwiftUI + SpriteView = Gray screen

347 Views Asked by At

Xcode 13 beta 2, iOS 15 beta 2.

The following code produces a gray screen:
(The SKScene GameScene.didMove(to:) never gets called)

import SwiftUI
import SpriteKit

// A simple game scene with falling boxes
class GameScene: SKScene {
    override func didMove(to view: SKView) {
        physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let location = touch.location(in: self)
        let box = SKSpriteNode(color: SKColor.red, size: CGSize(width: 50, height: 50))
        box.position = location
        box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
        addChild(box)
    }
}

// A sample SwiftUI creating a GameScene and sizing it at 300x400 points
struct ContentView: View {
    var scene: SKScene {
        let scene = GameScene()
        scene.size = CGSize(width: 300, height: 400)
        scene.scaleMode = .fill
        return scene
    }

    var body: some View {
        SpriteView(scene: scene)
            .frame(width: 300, height: 400)
            .ignoresSafeArea()
    }
}

I have no idea how to fix / workaround this issue.
Any thoughts?

(Works on previous Xcode / Swift version)

2

There are 2 best solutions below

0
backslash-f On BEST ANSWER

The issue is fixed in Xcode 13 beta 5 / iOS 15 beta 5.

1
Cenk Bilgen On

It could be because scene is a computed variable. So every time the view is redrawn or scene is accessed, it gets recomputed which creates and initializes a new GameScene object. Try something more like this, where GameModel and GameScene are only created once. (you can probably improve on it and remove having to set the size twice also):

class GameScene: SKScene { // keep the same }

class GameModel: ObservableObject {
  let scene: SKScene = {
    let scene = GameScene()
    scene.size = CGSize(width: 300, height: 400)
    scene.scaleMode = .fill
    return scene
  }()
}

struct ContentView: View {
    @StateObject var model = GameModel()
    var body: some View {
      SpriteView(scene: model.scene)
        .frame(width: 300, height: 400)
            .ignoresSafeArea()
    }
}