Swift 物理致命错误:当两个字符发生碰撞时,在展开可选值时意外发现 nil
Posted
技术标签:
【中文标题】Swift 物理致命错误:当两个字符发生碰撞时,在展开可选值时意外发现 nil【英文标题】:Swift Physics-fatal error: unexpectedly found nil while unwrapping an Optional value when two characters collide 【发布时间】:2015-07-18 00:14:35 【问题描述】:游戏背景:基本上你控制一个左右移动的角色并试图躲避掉落的方块。产生了三个玩家。一个在屏幕中间,两个正好 size.width 远离两边的中间播放器。
此错误仅在与 playerRight 或 playerLeft 或 Player 碰撞和掉落的方块的 10 次左右发生一次。正如您在下面的屏幕截图中看到的那样,玩家在坠落时似乎没有接触到坠落的方块。
错误代码和截图:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_l386_INVOP, subcode=0x0)
游戏场景如何停止
我认为这与我如何构建“无限”水平滚动播放器有关。基本上我有三个单独的字符,一旦中间字符超过 size.width 或低于 0,他在屏幕上的位置就会改变到屏幕的另一侧,基本上使其无限。也许玩家被传送到一个块内,它给出了一个零错误。不太确定,但似乎与此有关。无论如何,这是来自 GameScene 的相关代码。
import SpriteKit
import Foundation
import UIKit
//Collisions
struct PhysicsCategory
static let Enemy : UInt32 = 1
static let Player : UInt32 = 2
static let PlayerRight : UInt32 = 3
static let PlayerLeft : UInt32 = 4
static let EnemyRight : UInt32 = 5
var transition:SKTransition = SKTransition.fadeWithDuration(0.5)
class GameScene: SKScene, SKPhysicsContactDelegate
//Highscore Variable
var Highscore = Int()
//Score
var Score : Int = 0
var ScoreLabel = UILabel()
//Main Character
var Player = SKSpriteNode(imageNamed: "mainPlayer.png")
//Right-far character
var PlayerRight = SKSpriteNode(imageNamed: "mainPlayer.png")
//Left-far character
var PlayerLeft = SKSpriteNode(imageNamed: "mainPlayer.png")
//Holding vs Tapping Movement of Player
var isTouching = false
var touchXPosition:CGFloat = 0
override func didMoveToView(view: SKView)
/* Setup your scene here */
//Highscore
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
if (HighscoreDefault.valueForKey("Highscore") != nil)
Highscore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
else
Highscore = 0
//Collisions/Physics
physicsWorld.contactDelegate = self
//Background Color
scene?.backgroundColor = UIColor.blackColor()
//Spawn timer for enemy blocks
var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: Selector("spawnEnemies"), userInfo: nil, repeats: true)
//Timer for keeping score
var scoretimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("scoreCounter"), userInfo: nil, repeats: true)
//Player coordinates
Player.position.x = size.width * 0.5
Player.position.y = size.width * 0.11 / 2
//Setting Player Sizes
Player.size.width = size.width * 0.11
Player.size.height = size.width * 0.11
PlayerRight.size.width = size.width * 0.11
PlayerRight.size.height = size.width * 0.11
PlayerLeft.size.width = size.width * 0.11
PlayerLeft.size.height = size.width * 0.11
//Initial position of player
Player.position = CGPoint(x: Player.position.x, y: Player.position.y)
//Initial position of far-right player
PlayerRight.position = CGPoint(x: Player.position.x + size.width, y: Player.position.y)
//Initial position of far-left player
PlayerLeft.position = CGPoint(x: Player.position.x - size.width, y: Player.position.y)
//Adding Physics/Collisions to Player
Player.physicsBody = SKPhysicsBody (rectangleOfSize: Player.size)
Player.physicsBody?.affectedByGravity = false
Player.physicsBody?.categoryBitMask = PhysicsCategory.Player
Player.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
Player.physicsBody?.dynamic = false
//Adding Physics/Collisions to PlayerRight
PlayerRight.physicsBody = SKPhysicsBody (rectangleOfSize: PlayerRight.size)
PlayerRight.physicsBody?.affectedByGravity = false
PlayerRight.physicsBody?.categoryBitMask = PhysicsCategory.PlayerRight
PlayerRight.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
PlayerRight.physicsBody?.dynamic = false
//Adding Physics/Collisions to PlayerLeft
PlayerLeft.physicsBody = SKPhysicsBody (rectangleOfSize: PlayerRight.size)
PlayerLeft.physicsBody?.affectedByGravity = false
PlayerLeft.physicsBody?.categoryBitMask = PhysicsCategory.PlayerLeft
PlayerLeft.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
PlayerLeft.physicsBody?.dynamic = false
//Making Players visible
self.addChild(Player)
self.addChild(PlayerRight)
self.addChild(PlayerLeft)
//Making Score Visible
ScoreLabel.text = "\(Score)"
ScoreLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
ScoreLabel.font = UIFont(name: ScoreLabel.font.fontName, size:20)
ScoreLabel.textColor = UIColor.whiteColor()
self.view?.addSubview(ScoreLabel)
func scoreCounter()
//Setting score
Score += 1
ScoreLabel.text = "\(Score)"
func didBeginContact(contact: SKPhysicsContact)
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
//Checking for Player to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.Player))
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
else if (firstBody.categoryBitMask == PhysicsCategory.Player) && (secondBody.categoryBitMask == PhysicsCategory.Enemy)
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
//Checking for PlayerRight to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.PlayerRight))
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
else if (firstBody.categoryBitMask == PhysicsCategory.PlayerRight) && (secondBody.categoryBitMask == PhysicsCategory.Enemy)
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
//Checking for PlayerLeft to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.PlayerLeft))
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
else if (firstBody.categoryBitMask == PhysicsCategory.PlayerLeft) && (secondBody.categoryBitMask == PhysicsCategory.Enemy)
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
func CollisionWithEnemy(Enemy: SKShapeNode, Player: SKSpriteNode)
//Highscore
var ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
if (Score > Highscore)
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
//var gameOver:SKScene = GameOverScene(size: self.size)
//ScoreLabel.removeFromSuperview()
Enemy.removeFromParent()
//Player.removeFromParent()
//self.view?.presentScene(gameOver, transition: transition)
func CollisionWithEnemy2(Player: SKSpriteNode, Enemy: SKShapeNode)
//Highscore
var ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
if (Score > Highscore)
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
//var gameOver:SKScene = GameOverScene(size: self.size)
//ScoreLabel.removeFromSuperview()
Enemy.removeFromParent()
//Player.removeFromParent()
//self.view?.presentScene(gameOver, transition: transition)
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent)
/* Called when a touch begins */
isTouching = true
for touch in (touches as! Set<UITouch>)
let location = touch.locationInNode(self)
touchXPosition = location.x
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent)
isTouching = false
func spawnEnemies()
//Randomizing width of blocks
var blockWidth = Int(arc4random_uniform(UInt32(size.width / 3)) + UInt32(size.width / 5))
//Min and Max position of blocks
var minPosition : UInt32 = UInt32(blockWidth / 2)
var maxPosition : UInt32 = UInt32(size.width - CGFloat(blockWidth / 2))
//Randomizing Block Position
var blockXPosition = arc4random_uniform(maxPosition - minPosition) + minPosition
//Making Blocks
var Enemy = SKShapeNode(rectOfSize: CGSize(width: blockWidth, height: 5))
Enemy.position = CGPointMake (CGFloat(blockXPosition), CGFloat(size.height+50))
//Coloring Blocks
Enemy.fillColor = SKColor.whiteColor()
//Moving Blocks
let action = SKAction.moveToY(-50, duration: 2.5)
//Removing blocks once off screen
let actionDone = SKAction.removeFromParent()
//Running the above actions
Enemy.runAction(SKAction.sequence([action, actionDone]))
//Physics/Collisions
Enemy.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize (width: blockWidth, height: 1))
Enemy.physicsBody?.categoryBitMask = PhysicsCategory.Enemy
Enemy.physicsBody?.affectedByGravity = false
Enemy.physicsBody?.dynamic = true
//Adding enemy to scene
self.addChild(Enemy)
override func update(currentTime: CFTimeInterval)
/* Called before each frame is rendered */
var offsetLeft = 0 - (Player.position.x - 25)
Player.position = CGPoint(x: Player.position.x, y: Player.position.y)
PlayerRight.position = CGPoint(x: Player.position.x + size.width, y: Player.position.y)
PlayerLeft.position = CGPoint(x: Player.position.x - size.width, y: Player.position.y)
if isTouching
if touchXPosition > self.size.width / 2
// move character to the right.
Player.position.x += 10
if touchXPosition < self.size.width / 2
// move character to the left.
Player.position.x -= 10
if Player.position.x < 0
Player.position.x = size.width
if Player.position.x > size.width
Player.position.x = 0
所有内容都得到了很好的评论,但如果您对什么有任何疑问,请告诉我。对此的任何帮助将不胜感激!
【问题讨论】:
请不要粘贴代码、错误消息等的屏幕截图。粘贴代码。粘贴错误信息。解释问题。不要让人们处理代码图像。 我的坏人我会相应地更新它。 请不要“删除”您的问题 - 如果您找到解决方案,您可以回答自己的问题 【参考方案1】:static let PlayerRight : UInt32 = 3 //00000000000000000000000000000100
static let PlayerLeft : UInt32 = 4 //00000000000000000000000000001000
static let EnemyRight : UInt32 = 5 //00000000000000000000000000010000
您真的相信 3 是二进制 100
并且 4 是二进制 1000
(等等)?因为如果你这样做了,如果你需要它是真实的,那么如果你尝试使用这些值作为实际的位掩码,你以后会遇到很大的麻烦。
【讨论】:
老实说,我不知道,但我认为这对我的代码无关紧要。我正在看一个教程,这就是那个人说的,如果他们不是,他们会很抱歉。我会修复代码,尽管这并不重要,因为它们是 cmets。感谢您指出这一点。 @Darkstar 我猜你错过了1 << 3
1 << 4
等等,那么它(几乎)是正确的
是的,理解你一起复制的代码并不重要。只需将它置换,直到它“有点工作”,然后我们将完成剩下的工作。如果没有,只需将其发布在商店中即可。 :)以上是关于Swift 物理致命错误:当两个字符发生碰撞时,在展开可选值时意外发现 nil的主要内容,如果未能解决你的问题,请参考以下文章