I have a game project with two targets, one for macOS and one for iOS. I want to use the same SKScene
file for both. I add the SKS
file and set the targets as follows:
Usually, to load an SKS
file, I would use the following in the view controller:
override func viewDidLoad() { super.viewDidLoad() if let view = self.view as? SKView { if let scene = GameScene(fileNamed: "GameScene" ) { scene.scaleMode = .aspectFill view.showsFPS = true view.showsNodeCount = true view.showsPhysics = true view.presentScene(scene) } } } }
I call my SKScene
subclass with the init(fileNamed:)
method and it would load the SKS
file with my subclass as the root node.
However, I want to use the GameplayKit features that are now supported in SKS
files. To do this, I have to do it a little bit differently.
From Apple’s Game template for iOS:
override func viewDidLoad() { super.viewDidLoad() // Load 'SceneSelection.sks' as a GKScene. This provides gameplay related content // including entities and graphs. if let scene = GKScene(fileNamed: "SceneSelection") { // Get the SKScene from the loaded SceneSelection if let sceneNode = scene.rootNode as! SceneSelection? { // 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 } } } }
I use the init(fileNamed:)
initialiser of **GKScene**
to load the gameplay related content, then cast the rootNode
of that to my custom class and present that.
This means that I have to make sure that the root node is set to my custom class within the SKS
file:
However, when I added a new target (for macOS) and went to use the same SKS
file for both, it would fail to load on macOS with the following error:
GKScene unable to load custom class from module ‘(null)’
My understanding is that if you leave a module name blank, it’s supposed to just look in the main bundle for the correct class. The class was included in both targets, so it should have found it.
After a little bit of digging, I found a workaround. If I made the target -> Build Settings -> Product Module Name
identical for both targets:
Then set the module name in the SKS
file to that same module name:
Then everything would work as expected—it would load correctly on both iOS and macOS:
I don’t love having the same Product Module Name
for both targets—I’m not sure if that’s going to cause any other issues down the line—but it does work.
For some reason, this only happened when I added a brand new SKS file to an existing project and then tried targeting both macOS and iOS.
When I tried to recreate this issue using the default iOS game with Apple’s Game template, then added a new macOS target with the same template and had them both using the same GameScene.sks
and GameScene.swift
files, this issue didn’t reappear.
I don’t know if it’s because I was using Cocoapods in the original project or if its just some bad Xcode weather, but this is what got it to work.
If you know why this got it to work, I would love to know!