SpriteKit iOS 13 Swift 4 textures nil

So I have been working on a game using SpriteKit, utilizing the scene editor. Has been working very nicely, up until I was required to update to the latest SDK. I have been too busy lately and haven't gotten to work on it again until now... so it was flawless when I was running iOS 12 on my XS. My device is now iOS 13.3, which forced me to update to the latest version of Xcode (11.2?). Now, my app crashes, all textures from every SKSpriteNode in the scene are nil when getting references to them. They load just fine in the scene editor itself. In code, however, in the sceneDidLoad override, all of my childnode calls succeed in getting the SKSpriteNode reference, but texure is always nil... which then blows up my texture based PhysicsBody instansiations. The scenes entities structure also seems empty (so I'm not sure how I'm getting references to SKSpriteNodes, but I am). Just seems like GKScene fromFilename is loading an empty shell of my sks file.


This a known issue with the new tools? What did Apple change to break this? Anything new introduced that I need to be initializing? Should I be forced to update the project to Swift 5 to get rid of the issue? Not the first time Apple has changed something drastic in the application lifecycle that completely breaks every one of my apps, and I have to scrounge around for a different way to initialize the various components to get things to work again. Frankly I'm getting sick of it, spending more time fixing things from the complete disregard for any semblance of backwards compatibility in these SDKs than I do creating new functionality.


Thank you 🙂

Accepted Reply

Texture Alpha Masks are the issue.

You can find some discussion about the similar issue on StackOverflow:

- stackoverflow.com/questions/58544851/creating-a-physics-body-using-a-textures-alpha-channel-not-working-in-xcode-11


So, it is very likely your issue might be a bug of Xcode/iOS SDK.


that's likely going to require me to wait for iOS 13.3.1, or whatever, hotfix release

Apple would not fix it unless it is recognized as needs to be fixed. You should better send a bug report as soon as possible.


Before sending a bug report, you should better confirm:

- You use the latest Xcode, which is 11.3 released on December 10. Do not forget to restart your Mac after updating Xcode.

- Create a minimized project which reproduces the same issue, Apple may need the very sks file.


Unfortunately I could not have found any steady workaround on the Web.


One more, you should better post this on the more appropriate topic area: SpriteKit Graphics framework for 2D games

Replies

Yes, it (often) occurs that lifecycle changes.


The problem is (often) that we relied on undocumented behavior that did work. But was not guaranteed to work. And it crashes in new versions.


This said, I agreed (because I did get those problems) that they are poorly (to says the least) documented.


One thing to look at, is that, in viewDidLoad a lot of outlets are not yet present. So thay are not initialized.

It may be better to set them later, like viewWillLayout.


Could somethging similmar occur with sceneDidload? (doc seems to tell the contrary).

Coulmd you post some code ?

This is a snippet from where I'm loading the scene from the sks file:


if let scene = GKScene(fileNamed: level.File) {

// 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;

....


The GKScene load above is being triggered by an UIButton touch up from my main view controller. The GKScene instantiation is what is firing off the sceneDidLoad callback within my GameScene class.


Inside my sceneDidLoad I have a pile of these for masks, objects, enemies, emitters, etc.

let firstMask = self.childNode(withName: "//Mask") as? SKSpriteNode;

let player = self.childNode(withName: "//Player") as? SKSpriteNode;


then, where it crashes is here, because texture is nil:

mask.physicsBody = SKPhysicsBody(texture: mask.texture!, size: mask.size);


Now, what's odd, is that both "Mask" and "Player" exist in my scene editor, and as I said worked in iOS 12 just fine... The element "Mask" above IS loading into the variable firstMask, but it's texture and other properties are nil. "Player" is in my scene editor just fine as it always was too... but that player variable is coming back nil. It's almost acting like sceneDidLoad isn't finished loading the scene really, and my first few childNode calls are getting "something", but then later ones are not.


If I comment out all of my sceneDidLoad code the next line to capture my sceneNode fails, because scene.rootNode is also null.

if let sceneNode = scene.rootNode as! GameScene? {


The entire GKScene call is just simply failing to load my file, and it makes no sense. Like Apple changed the structure of the file, but aren't throwing any errors about it failing to load, just handing back an empty trash structure of partially loaded elements and mostly nils.


The whole viewDidLoad vs. viewWillLayout is exactly what I had to battle with back when I was doing some raw OpenGL stuff. But I don't see any similar overrides for SpriteKit. There's sceneDidLoad, didChangeSize, and willMove, that's about it. No others than sceneDidLoad seem applicable to initialization here for me to move my initialization code to.


I guess my next step is to try and create a new sks file with the new version of Xcode to see if that one loads as a GKScene properly. If that works, I'm not going to be happy. I have countless hours into creating these game files, and I don't want to have to redo them all (already tried just opening and resaving one, that didn't make a difference).

SURE ENOUGH, creating a brand new sks file DOES load and work properly. Objects loaded, rootNode was not nil. None of the 40+ sks files that I created using Xcode 10 and the older SDKs load. They all flake out with mostly nil values and a nil rootNode.


There has got to be a way to get these to work again without having to recreate my entire book of content. That's enough to simply make someone dump the entire ecosystem and simply forget about it. Imagine if I had 10 other games out there already and this happened? Holy mother of...

More information. I rebuilt one level up to the point it stopped working too.


Texture Alpha Masks are the issue. I use them all over the place, because my levels contain complex winding tunnels. If there's an alpha mask in the level it ***** 😟 This isn't some lifecycle change during initialization, it's a full out bug that's likely going to require me to wait for iOS 13.3.1, or whatever, hotfix release before I can continue development.

Texture Alpha Masks are the issue.

You can find some discussion about the similar issue on StackOverflow:

- stackoverflow.com/questions/58544851/creating-a-physics-body-using-a-textures-alpha-channel-not-working-in-xcode-11


So, it is very likely your issue might be a bug of Xcode/iOS SDK.


that's likely going to require me to wait for iOS 13.3.1, or whatever, hotfix release

Apple would not fix it unless it is recognized as needs to be fixed. You should better send a bug report as soon as possible.


Before sending a bug report, you should better confirm:

- You use the latest Xcode, which is 11.3 released on December 10. Do not forget to restart your Mac after updating Xcode.

- Create a minimized project which reproduces the same issue, Apple may need the very sks file.


Unfortunately I could not have found any steady workaround on the Web.


One more, you should better post this on the more appropriate topic area: SpriteKit Graphics framework for 2D games

Thank you.


Now what I'm unsure of, is if it's a bug in the iOS 13 SDK? Or iOS 13 on the devices themselves? I'm guessing the SDK, because if every game on the App Store that uses texture physic masks broke there'd be a much bigger outcry. Or maybe there is and we just don't hear about it p, because its being directed at the developers themselves via negative reviews.


I can't backdate my phone to 12.4 again, that window is already closed, Can't use the simulators, my game depends on constant gyroscopic movement... can't even begin to test with a simulator. I'm stuck waiting for a fix 😟

As discussed in various stackoverflow threads, physics bodies from textures was completely broken in 13.0 and 13.1. It was partially fixed in 13.2 in that it works for textures that are not in atlases. I haven't checked 13.3 specifically yet since we worked around the issue by adding duplicate not-in-atlas versions of textures just for making physics bodies (and by falling back to a convex-hull approach when running under 13.0 and 13.1). As a suggestion to try to get something working, see if you can remove anything that needs a texture-based physics body from an altas.

So it “is” an issue with iOS itself, given that you have backup methods in place in case the user is running 13.0 or 13.1? None of my physics bodies from texture are coming from an atlas, and under 13.3 completely broken. Not a case of them acting funny, but rather the entire sks fails to load. Convex hull approach is far too much work for my game. Based on how little time I get to work on it, the majority of devices out there will be running iOS 14 before I’m ready to release.

We don't use sks files but do everything programmatically, so I don't know what might be happening under the hood there. Unfortunately I only have two physical devices, one with iOS 12.4 and one now with 13.3. I can't say for sure whether the issue has to do with the device's iOS version or with the Xcode version and libraries instead, but our code has two paths when making a physics body. One for iOS 13.0 and 13.1 where it uses a convex hull, and one for everything else where it uses the texture but not from an atlas. Upgrading from 13.2 to 13.3 didn't break it, so I assumed 13.3 was at least as working as well as 13.2 when it came to making physics bodies. I also assumed a 13.1 device would still be broken, but don't have one to test. Simulator testing never showed a problem, but it wasn't practical in our case.

That's my problem too, simulator isn't practical for the nature of my game. All of my devices are 13.3 as well 😟. Hope it's just an SDK problem... going to seem silly to have an AppStore description of "Supports iOS 12 and up (except 13.0 - 13.3!)".

Oh my, luck of luck... just found that my kids device is still 12.4, I can actually get some work done.

Revisiting this... iOS 13.3.1 and still to fix in sight.

iOS auto update strikes again... I'm out of luck again. No iOS 12 devices in the house anymore.


Found the following today:

https://github.com/bg2b/bugtest


May be some workarounds in there that may help someone. I haven't tried it myself yet to see if it will helo my situation.

I've also been struggling with this for weeks. I tried the github workaround (saw it on StackOverflow as well), but no luck for my game. Everything works fine in the simulator, but on the device:


PhysicsBody: Could not create physics body.


gets spammed in the console with most of the sprites not rendering.


Downloading iOS 13.4.1 now...

I have a support assistant ticket going that has been getting some response from Apple that they are working on it, and will have something in a future release. In the meantime, they offer the following workaround below. I haven't had luck with it yet. Yes, I don't get the crash on the physics body creation if i follow the step below if not setting them up in the sks file, but instead I'm now crashing because half of my nodes in fetching by name are coming back nil instead now, one of them being the camera!


Maybe you'll have better luck with this:


Apple suggested workaround:
----------------------------------------------

1. Set physics body type of problematic sprites to “None” in the .sks file.

2. Generate and set the physics bodies at runtime using SKPhysicsBody.init(texture:alphaThreshold:size:)


Here is an example of the suggested workaround applied in our Xcode Game Template with SpriteKit and GameplayKit selected:


// 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

// Generating physicsBody for sprites at runtime based on their texture’s alpha channel.

sceneNode.children.forEach {

if let sprite = $0 as? SKSpriteNode,

let texture = sprite.texture {

sprite.physicsBody = .init(texture: texture, alphaThreshold: 0.1, size: sprite.frame.size)

}
}
// Present the scene
if let view = self.view as! SKView? {
view.presentScene(sceneNode)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
view.showsPhysics = true
}
}


----------------------------------------------