0

I am currently making a game in which you are a space ship in the middle and there are enemy ships moving towards you and you have to shoot at them to win.

While I was testing the game I saw that I received an error when (it appears to be) two or more enemy ships hit the player ship at the same time. I am not certain if this is what's causing the error but it looks like it when I test it.

I made the game so that whenever enemy players touch the player, the game ends and a function is called to change the game scene. This is where the error is called, whenever the scene is about to change.

"fatal error: unexpectedly found nil while unwrapping an Optional value"

here is the code for the didBegin(contact: SKPhysicsContact)

func didBegin(_ contact: SKPhysicsContact) {

    var BodyOne = SKPhysicsBody()
    var BodyTwo = SKPhysicsBody()


    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask{
        BodyOne = contact.bodyA
        BodyTwo = contact.bodyB
                }
    else{
        BodyOne = contact.bodyB
        BodyTwo = contact.bodyA
    }


    //SHIPS TOUCH EACH OTHER CHECK
    if BodyOne.categoryBitMask == NumberingPhysics.SpaceShip && BodyTwo.categoryBitMask == NumberingPhysics.LeftV{



        GameOver1()

       BodyTwo.node?.removeFromParent()
       BodyOne.node?.removeFromParent()

    }

    if BodyOne.categoryBitMask == NumberingPhysics.SpaceShip && BodyTwo.categoryBitMask == NumberingPhysics.RightV{

        GameOver1()
        BodyOne.node?.removeFromParent()
        BodyTwo.node?.removeFromParent()


        //more code is under here 

    }

And here is the code of the game changing scene. (which works when 1 enemy touches the player but doesn't seem to when 2 or more makes contact with the player)

func GameOver1(){

    ButtonAudioPlayer.stop()
    removeAllChildren()
    removeAllActions()
    let scene = GameOver(size: self.size)
    let sKView = self.view! as SKView       // <----- error shows here
    sKView.ignoresSiblingOrder = true
    scene.scaleMode = .aspectFill
    sKView.presentScene(scene)


}

Can someone please help me resolve this issue.

Chris
  • 2,435
  • 6
  • 26
  • 49
Alex Merlin
  • 341
  • 1
  • 3
  • 12
  • We don't know where you are calling GameOver1. If you are calling it within a scene, it can crash. – El Tomato Jul 04 '17 at 01:42
  • 1
    Multiple contacts can happen in 1 frame between 2 different objects, you are killing your sprite too early – Knight0fDragon Jul 04 '17 at 01:46
  • 1
    Possible duplicate of [SpriteKit game crashes when two SKPhysicsContacts are detected](https://stackoverflow.com/questions/43058602/spritekit-game-crashes-when-two-skphysicscontacts-are-detected) – Knight0fDragon Jul 04 '17 at 01:50
  • Where is `GameOver1` defined? Inside of your scene that calling `didBegin`? – Fluidity Jul 04 '17 at 02:04
  • Yes. it is defined in the same scene that is calling didBegin. If it is not supposed to be defined there, where is it supposed to? – Alex Merlin Jul 04 '17 at 20:07

1 Answers1

2

Your view object is nil, which is peculiar if you are defining GameOver1 inside of the active scene. Move your GameOver1 function to your main scene, and that should fix the issue.

Or, you could make a global variable and assign it to the initial SKView object inside of your GameViewController. This is not a best practice but it will work.

var gView = SKView()

class GameViewController: UIViewController {
  // Stuff..

  if let view = self.view as! SKView? {
      gView = view

Also, you have other potential crash issues in this code.

As KOD said in comments multiple contacts can happen in 1 frame.. but you are killing the node (and thus pb) which means the scheduled .didBegin is going to find nil or some other error and crash.

A better way to do this is to flag the node for removal AFTER the physics step--once contacts are safely handled.

Set their mask to some high-number instead of removing it:

var nodesToKill = SKNode()

override func didBeginContact(/*prams*/) {
  // Stuff...

  BodyB.node!.categoryBitMask = 35 // Or some other number so as 
                                   // to not trigger another contact.
  BodyB.node!.moveToParent(nodesToKill) //moves the node off the scene entirely
}

override func didSimulatePhysics(/*prams*/) { 

  nodesToKill.removeAllChildren() // or do nodesToKill = SKNode() and let ARC take care of it for you
}

Also, you probably want to all of the node removal stuff BEFORE calling GameOver, as that can cause issues as well with trying to do stuff with nodes that no longer exist.

A somewhat contrived way around this (if the above didn't work) is something like this:

var flag_shouldGameOver = false

override func didFinishUpdate() {
  if flag_shouldGameOver == true {
     flag_shouldGameOver = false
     GameOver1()
  }
}
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
Fluidity
  • 3,985
  • 1
  • 13
  • 34
  • 1
    Updated to avoid the array, keeps it in Sprite Kit functionality, and removes the node from the scene without nil crashing – Knight0fDragon Jul 04 '17 at 02:38
  • @Fluidity can you tell me how am I supposed to call the GameOver1() function if the function is defined in another game scene ? Thank You – Alex Merlin Jul 04 '17 at 20:23
  • @AlexMerlin youre not. i dont see how your view is nil if called by the presented scene. – Fluidity Jul 04 '17 at 20:46
  • try the gView idea it cant crash. 'gView.presentScene' etc – Fluidity Jul 04 '17 at 20:47
  • @Fluidity hey I am sorry for the delay. The only thing I changed was instead of removing the node from the parent before calling the GameOver scene was that I changed the body's categoryBitMask to a high number. I tested the game several times and I don't seem to get the error anymore. Do you think this might have been the problem? – Alex Merlin Aug 10 '17 at 16:32
  • @AlexMerlin I'm going to say "yes" though I'm not 100% certain why... to me it seemed that you had a `nil` view object. In normal circumstances (where you aren't changing the scene) removing a node is generally a good way to crash your app via subsequent (but inintended) `didBegin` calls. I'm guessing that `didBegin` was being called again despite you requesting a scene change. I'm not sure though, but it would be a cool thing to test out. – Fluidity Aug 10 '17 at 17:36
  • the takeaway here is that you learned to not remove nodes in `didBegin` :) – Fluidity Aug 10 '17 at 17:36
  • @Fluidity Hey, where did you learn all of this stuff about swift, spritekit, etc. you know, so I can learn things myself and stop bothering you guys lol. – Alex Merlin Aug 24 '17 at 15:24
  • I learned the basics from books and tutorials / articles. All of the "advanced" stuff I learned through a year of helping people on SO, and kind of forcing myself to figure crap out. So in essence, people asking a bunch of questions kind of taught me... There is also some stuff you can find on the WWDC converence videos for spritekit from the past few years. Honestly, SK isn't but so popular or there would be "advanced SpriteKit" books that cover the stuff we had to figure out ourselves.. Also, Apple could have done a better job going over advanced stuff. @AlexMerlin – Fluidity Aug 25 '17 at 03:43
  • @AlexMerlin this question was pretty simple though, because you are force unwrapping something, which is pretty obvious what is causing the crash... you just backtrack from there. – Fluidity Aug 25 '17 at 03:47
  • also, KoD for example has decade(s) of professional game dev experience... so picking up something like SK isn't as difficult when you already know the basics of what you are doing.... In otherwords, SK is a tool, and all the books and junk are just to teach you how to use SK... not necessarily how to be a game programmer / designer... And most of the books / articles are just "click here, do that" instead of actually making you think _why am I doing something_ and to learn critical thinking / problem solving. – Fluidity Aug 25 '17 at 04:02
  • @AlexMerlin here is how I learned, exactly 1 year ago today I answered my first SpriteKit question. I had pretty much no idea what I was doing or what I was talking about (faking it till making it I guess).. but basically I sat down with someone's question, then took the next few hours to figure it out, posted the answer, and huzzah it worked. Rinse and repeat x130 over a year :P https://stackoverflow.com/questions/39149404/building-a-spritekit-gamekit-leaderboard-within-a-specific-scene/39153023#39153023 – Fluidity Aug 25 '17 at 04:12
  • @Fluidity Wow your a pretty smart guy. I will start doing that as well so I can learn all these things you know. Ill also try to start answering some questions. Thank you for the info and help. – Alex Merlin Aug 31 '17 at 04:18
  • @Fluidity btw Happy anniversary on your first question lol :) – Alex Merlin Aug 31 '17 at 04:20