Search code examples
swiftsprite-kittexturesskphysicsbody

Found nil when unwrapping texture value which I have previously set


so I am trying to add an SKSpritenode to my scene level2, and I want to give it a physics body with a texture that comes from an image I have uploaded into the assets folder of my project. the image is there and the name is right, but when launch the app I get a fatal error. I don't get where I'm going wrong as the app used to run smoothly until I added that last line of code.

import UIKit
import SpriteKit 
import GameplayKit

class level2: SKScene {

    var entities = [GKEntity]()
    var graphs = [String : GKGraph]()

    var perno = SKSpriteNode(fileNamed: "perno")

    override func sceneDidLoad () {
        print ("view2 Loaded")

        self.perno  = self.childNode(withName: "perno") as? SKSpriteNode
        self.perno?.texture = SKTexture(imageNamed: "perno")
        self.perno?.size.width = self.perno!.size.width * 5

        self.perno!.physicsBody = SKPhysicsBody(texture: (perno?.texture)!, size: (perno?.texture?.size())!)



}

any hints?

Thanks!


Solution

  • Your optional handling is really inconsistent. Sometimes you use optional casting and optional chaining just to then use force unwrapping on the same variable in the same line. You should force unwrap the return value of SKSpriteNode(fileNamed: "perno"), since if that returns nil that's a programmer error and should be caught ASAP.

    Your immediate issue seems to be that you try to overwrite perno in sceneDidLoad:

    self.perno  = self.childNode(withName: "perno") as? SKSpriteNode
    

    There's no childNode added to your scene, so you just set perno to nil instead of its previously set value using var perno = SKSpriteNode(fileNamed: "perno"). Simply remove that line from sceneDidLoad, since it makes no sense, perno is already loaded during initialisation, since you assign a value to it.

    class Level2: SKScene {
    
        var entities = [GKEntity]()
        var graphs = [String : GKGraph]()
    
        let perno = SKSpriteNode(fileNamed: "perno")!
    
        override func sceneDidLoad () {
            print ("view2 Loaded")
            self.perno.texture = SKTexture(imageNamed: "perno")
            self.perno.size.width = self.perno.size.width * 5
    
            self.perno.physicsBody = SKPhysicsBody(texture: perno.texture!, size: perno.texture!.size())
        }
    
    }
    

    A better way to protect yourself is to use the guard statement. guard allows you to safely check if a variable is not nil without having to nest your code.

    class Level2: SKScene {
    
        var entities = [GKEntity]()
        var graphs = [String : GKGraph]()
    
        let perno = SKSpriteNode(fileNamed: "perno")!
    
        override func sceneDidLoad () {
            print ("view2 Loaded")
            guard let texture = SKTexture(imageNamed: "perno")
            else{
                fatalError("Unable to find texture "perno")
            }
            self.perno.texture = texture
            self.perno.size.width = self.perno.size.width * 5
    
            self.perno.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
        }
    
    }
    

    As you can see, we are not excessively unwrapping self.perno.texture, which means there will be less chances for us to accidentally use a ? instead of a !, and we have a clear cut error as to why our code is crashing.