Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a custom GKComponent to an entity in Xcode SpriteKit scene editor sets GKScene.rootNode to nil

When I add a CustomComponent (GKComponent) to an entity in Xcode SpriteKit scene editor and try to load that .sks file using a GKScene.init, GKScene.rootNode is not set. Even stranger, this happens only on iOS 13 and not on iOS 12.

I have a small sprite kit github project setup that demonstrates this issue clearly. Just run the app on an iOS 13 emulator to reproduce the issue. https://github.com/hdsenevi/answers-gkscene-rootnode-nil-bug

If I remove CustomComponent from SpriteKit scene editor entity/sprite, then it runs fine. ie: loads SKScene into GKScene.rootNode

  1. Is there any other special modifications that needs to happen when adding GKComponents from Xcode SpriteKit scene editor?
  2. Am I missing something obvious here?
  3. And why would this code work without an issue on iOS 12 and not iOS 13?
  4. Has SpriteKit functionality changed with regards to this in iOS 13?

For reference

import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Load 'GameScene.sks' as a GKScene. This provides gameplay related content
        // including entities and graphs.
        if let scene = GKScene(fileNamed: "GameScene") {

            // Get the SKScene from the loaded GKScene
            if let sceneNode = scene.rootNode as! GameScene? {

                // Copy gameplay related content over to the scene
                sceneNode.entities = scene.entities
                sceneNode.graphs = scene.graphs

                // Set the scale mode to scale to fit the window
                sceneNode.scaleMode = .aspectFill

                // Present the scene
                if let view = self.view as! SKView? {
                    view.presentScene(sceneNode)

                    view.ignoresSiblingOrder = true

                    view.showsFPS = true
                    view.showsNodeCount = true
                }
            } else {
                print("Error. No GameScene was found on GKScene.rootNode")
            }
        } else {
            print("Error loading GKScene file GameScene")
        }
    }
}
import SpriteKit
import GameplayKit

class CustomComponent: GKComponent {
    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func didAddToEntity() {
        guard let gkSkNodeComponent = self.entity?.component(ofType: GKSKNodeComponent.self) else {
            print("Error. Cannot obtain a reference to GKSKNodeComponent")
            return
        }

        if let sprite = gkSkNodeComponent.node as? SKSpriteNode {
            sprite.texture?.filteringMode = .nearest
        }
    }
}

Update

Few details on my setup

  • macOS Mojave 10.14.6
  • Xcode 11.0 (tried on 10.1 and 10.3, same behaviour)
like image 432
hdsenevi Avatar asked Oct 05 '19 03:10

hdsenevi


1 Answers

To solve the problem, your component needs to override variable supportsSecureCoding and it must return true.

This worked for me:

override class var supportsSecureCoding: Bool {
    return true
}
like image 130
GoSti0 Avatar answered Oct 05 '22 04:10

GoSti0