问题
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.
回答1:
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()
}
}
来源:https://stackoverflow.com/questions/44895717/receiving-an-error-when-nodes-make-contact