1

I am creating a game where character jumps and collect points (SOME OBJECT). When you tap character perform some animation from atlas. When it touches the points, score is increased by 1. I am using SKTexture to create physicbody of the character. When my character touches the point it crashes and show me this error

fatal error: unexpectedly found nil while unwrapping an Optional value 

//Code

 Cat = SKSpriteNode(imageNamed: "cat");
  Cat.size = CGSize(width: 100, height: 100)
  Cat.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)

  //physics 
  Cat.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "cat"), size:CGSizeMake(100, 100))

But if i create Physicsbody from rectangle or circle it works just fine. Maybe its to do with atlases i am using to animate my character.

Cat.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.width/2)

When the character touches the mushroom it crashes. Working Demo: https://github.com/nak1b/demo-game-error

Nakib
  • 4,593
  • 7
  • 23
  • 45
  • See if this helps in any way : http://stackoverflow.com/a/36610484/3402095 – Whirlwind May 01 '16 at 21:05
  • @Whirlwind it didnt help – Nakib May 02 '16 at 02:22
  • Okay, so which line of code crashes ? – Whirlwind May 02 '16 at 02:45
  • bodyA.removeFromParent() – Nakib May 02 '16 at 04:02
  • Have you checked that SKTexture(imageNamed: "cat") is not returning nil? – Ali Beadle May 02 '16 at 05:36
  • 1
    @AliBeadle `convenience init `imageNamed` Can't return nil. It searches the bundle for an image, then if needed continues with search through atlases, and if that fails as well, it creates a placeholder texture image (missing resource image). – Whirlwind May 02 '16 at 13:52
  • @Nakib It is odd that it works with rectangular physics body and not with the one created from a texture, but still you haven't provided [mvce](http://stackoverflow.com/help/mcve) so I can't comment on this no more. It may happen that your image is too complex though. – Whirlwind May 02 '16 at 14:00
  • @Whirlwind i will provide sample running demo later today. – Nakib May 02 '16 at 17:16
  • @Whirlwind i have created a simple demo. https://github.com/nak1b/demo-game-error. When the character touches the mushroom game crashes. – Nakib May 03 '16 at 05:13

1 Answers1

2

The problem with your code is that didBeginContact is being called multiple times... You can check this by putting a print() statement inside of that if block.

As you already know, an SKPhysicsBody object has a property called node. It is an optional property. It represents the node that this body is connected to. In your case that is a mushroom node.

So when didBeginContact is called for the first time, because you remove a mushroom node from its parent, bodyA.node becomes nil. Next time doing bodyA.node!.removeFromParent() will produce a crash, because, as I said, bodyA.node is now nil but you are using forced unwrapping to access underlying value of an optional.

Use forced unwrapping only when you are 100% positive that underlying value is not nil (or if you intentionally want to trigger an error during the development phase). Otherwise use optional binding or optional chaining. Like this:

func didBeginContact(contact: SKPhysicsContact) {

    var firstBody, secondBody: SKPhysicsBody

    //Do this to avoid double checking
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {

        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {

        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    //No need for double-checking now
    if ((firstBody.categoryBitMask & PhysicsCategory.Panda) != 0 &&
        (secondBody.categoryBitMask & PhysicsCategory.Score != 0)) {

            //This will fail gracefully if node property is nil
            secondBody.node?.removeFromParent()
    }
}
Whirlwind
  • 14,286
  • 11
  • 68
  • 157
  • thanks for all your help bud. I will try this and mark it as helpful answer. Can you explain why this works when physics body is assign using circle or rectangle. – Nakib May 03 '16 at 14:29
  • @Nakib I can't go into details, because it is not documented how SpriteKit internally handles contact detection for differently shaped physics bodies... In your case, what I can see, is that `didBeginContact` is called only once if you create a rectangular physics body. So you never run into situation where the `bodyA.node` is `nil`. That's why it works ( means there is no crash). Still, as you can see, a forced unwrapping is not a safest way to go. – Whirlwind May 03 '16 at 17:00
  • this fixed the crashing but i have scoreGenerator() inside didbeginContact. Once mushroom is removed it generates it again at random position. By Changing the code to above it is now calling that function continuously. – Nakib May 04 '16 at 04:53
  • @Nakib I assume that you mean `generateScoreNode()` instead of `scoreGenerator()`. If so, what you are seeing is related to your code logic. You are creating a mushroom at the same position every time. When a new mushroom is spawned, a contact between mushroom and a player occurs because player is actually moving. So mushroom get spawned, then immediately removed, then spawned, etc. An infinite loop. It is unclear to me what you are expecting to see though. What you are seeing is defined by you (means you haven't stated otherwise in your code). – Whirlwind May 04 '16 at 06:52
  • in the demo it generates the mushroom on fixed position but on an actual game it generates on random location. Thanks though i got everything working now :) – Nakib May 04 '16 at 18:50
  • @Nakib You are welcome. I am glad to hear you figured it out :) Happy coding! – Whirlwind May 04 '16 at 20:05