我有一个游戏,主角通过按下屏幕按钮向敌人(当前是炸弹)发射子弹,并试图避免掉落物体。目前我一次射击一颗甚至几颗子弹都没有问题。但是,在测试时,如果我一次拍摄一组(20到50之间),我会收到上述错误。有没有人有什么建议?我不知道为什么我的任何节点都是零。我怀疑我的子弹在退出屏幕时实际上并没有被移除,但这可能是一个不同的问题。
以下是获取错误的行:
func didBeginContact(contact: SKPhysicsContact) {
let firstNode = contact.bodyA.node as! SKSpriteNode
let secondNode = contact.bodyB.node as! SKSpriteNode - fatal error: unexpectedly found nil while unwrapping an Optional value
完整代码:
import SpriteKit
import CoreMotion
class GameScene: SKScene, SKPhysicsContactDelegate {
let joyStickSprite = SKSpriteNode(imageNamed: "flatLight09")
let leftButton = SKSpriteNode (imageNamed: "flatLight03")
let rightButton = SKSpriteNode (imageNamed: "flatLight04")
let jumpButton = SKSpriteNode (imageNamed: "flatLight24")
let fireButton = SKSpriteNode (imageNamed: "flatLight47")
let playerSprite = SKSpriteNode(imageNamed: "p3_front")
let enemySprite = SKSpriteNode(imageNamed: "bomb")
let bomb = SKSpriteNode(imageNamed: "bomb")
let floorSprite = SKSpriteNode(imageNamed: "floorGrass")
var coinSprite = SKSpriteNode(imageNamed: "gold_1")
var left = false
var right = false
var bullet: SKNode!
var motionManager = CMMotionManager()
var destY:CGFloat = 0.0
var scoreLabel: SKLabelNode!
var score = 0
var coinOnScreen = false
var explosion : SKSpriteNode!
var groundExplosionFrames : [SKTexture]!
struct CollisionCategoryBitmask {
static let Player: UInt32 = 0x1 << 0
static let Enemy: UInt32 = 0x1 << 1
static let Floor: UInt32 = 0x1 << 2
static let Coin: UInt32 = 0x1 << 3
static let bomb: UInt32 = 0x1 << 4
static let bullet: UInt32 = 0x1 << 5
}
var background = SKSpriteNode(imageNamed: "blue_land")
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
createBackground()
createPlayer()
createFloor()
createJoyStick()
createJumpButton()
createFireButton()
setUpLabels()
dropEnemy()
var wait3 = SKAction.waitForDuration(1.0)
var run3 = SKAction.runBlock {
self.bomb.removeFromParent()
self.createBomb()
}
self.runAction(SKAction.repeatActionForever(SKAction.sequence([wait3, run3])))
/*
var wait = SKAction.waitForDuration(5, withRange: 3)
var run = SKAction.runBlock {
self.coinSprite.removeFromParent()
self.createCoins()
}
self.runAction(SKAction.repeatActionForever(SKAction.sequence([wait, run])))
*/
//Load the TextureAtlas for the bear
let groundExplosianAnimatedAtlas : SKTextureAtlas = SKTextureAtlas(named: "GroundExplosion")
//Load the animation frames from the TextureAtlas
var explodeFrames = [SKTexture]()
let numImages : Int = groundExplosianAnimatedAtlas.textureNames.count
for var i=1; i<=numImages/2; i++ {
let explosionTextureName = "groundExplosion0\(i)"
explodeFrames.append(groundExplosianAnimatedAtlas.textureNamed(explosionTextureName))
}
groundExplosionFrames = explodeFrames
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.currentQueue()) {
[unowned self] accelerometerData, error in
var currentY = self.enemySprite.position.y
let acceleration = accelerometerData.acceleration
self.destY = (CGFloat(acceleration.y) * 0.75) + (self.destY * 0.25)
}
}
override func willMoveFromView(view: SKView) {
motionManager.stopAccelerometerUpdates()
removeAllChildren()
}
func groundExplosion() {
var explode = SKAction.runBlock({
self.enemySprite.runAction( SKAction.repeatAction(SKAction.animateWithTextures(self.groundExplosionFrames, timePerFrame: 0.05, resize: false, restore: true), count: 1), withKey:"groundExplosion")
self.enemySprite.physicsBody?.dynamic = false
})
var wait = SKAction.waitForDuration(0.2)
var remove = SKAction.runBlock({self.enemySprite.removeFromParent()})
var drop = SKAction.runBlock({self.createEnemy()})
var sequence = SKAction.sequence([explode, wait, remove, drop])
self.runAction(sequence)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(location)
if let name = touchedNode.name
{
if name == "joyStick"
{
if location.x < joyStickSprite.position.x {
left = true
right = false
}
else {
right = true
left = false
}
}
}
if let name = touchedNode.name
{
if name == "jumpButton"
{
if playerSprite.position.y < 100 {
self.playerSprite.physicsBody?.applyImpulse(CGVector(dx: 0.0, dy: 60.0))
}
}
if name == "fireButton"
{
makeBullet()
}
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
left = false
right = false
playerSprite.texture = SKTexture(imageNamed: "p3_front")
}
func setUpLabels () {
//set up labels
scoreLabel = SKLabelNode(fontNamed: "Arial")
scoreLabel.position = CGPoint(x: self.size.width/10, y: self.size.height - 30)
scoreLabel.text = String("Score \(score)")
scoreLabel.fontColor = UIColor.grayColor()
scoreLabel.fontSize = 35
self.addChild(scoreLabel)
}
func createBackground () {
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
background.size.height = self.size.height
addChild(background)
}
func createPlayer () {
playerSprite.position = CGPoint(x: self.size.width / 2, y: floorSprite.size.height/2)
playerSprite.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(playerSprite.size.width/2.5, playerSprite.size.height))
playerSprite.physicsBody?.dynamic = true
playerSprite.physicsBody?.allowsRotation = false
playerSprite.physicsBody?.friction = 100.0
playerSprite.physicsBody?.affectedByGravity = true
playerSprite.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Player
playerSprite.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Floor
playerSprite.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Enemy | CollisionCategoryBitmask.Coin | CollisionCategoryBitmask.bomb
addChild(playerSprite)
}
func movePlayerLeft () {
let moveLeft = SKAction.moveByX(-8, y: 0, duration: 0.5)
playerSprite.runAction(moveLeft)
}
func movePlayerRight () {
let moveRight = SKAction.moveByX(8, y: 0, duration: 0.5)
playerSprite.runAction(moveRight)
}
func makeBullet() {
var bullet = SKSpriteNode(imageNamed: "laserBlue01")
bullet.position = CGPointMake(playerSprite.position.x, playerSprite.position.y - 20)
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
bullet.physicsBody?.dynamic = true
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.categoryBitMask = CollisionCategoryBitmask.bullet
bullet.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.bomb | CollisionCategoryBitmask.Enemy
bullet.physicsBody?.collisionBitMask = 0
var movebullet = SKAction.moveByX(CGFloat (-400), y: 0, duration: 1)
var movebulletForever = SKAction.repeatActionForever(movebullet)
bullet.runAction(movebulletForever)
self.addChild(bullet)
}
func createEnemy () {
enemySprite.removeFromParent()
var randomX = Int(arc4random_uniform(600))
var randomXCG = CGFloat(randomX)
enemySprite.size.height = playerSprite.size.height/2
enemySprite.size.width = enemySprite.size.height
enemySprite.position = CGPoint(x: randomXCG, y: self.size.height - enemySprite.size.height/2)
enemySprite.physicsBody = SKPhysicsBody(circleOfRadius: enemySprite.size.width / 2)
enemySprite.physicsBody?.dynamic = false
enemySprite.physicsBody?.allowsRotation = false
enemySprite.physicsBody?.restitution = 0.0
enemySprite.physicsBody?.friction = 0.8
enemySprite.physicsBody?.angularDamping = 0.0
enemySprite.physicsBody?.linearDamping = 0.0
enemySprite.physicsBody?.affectedByGravity = false
enemySprite.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Enemy
enemySprite.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Floor
addChild(enemySprite)
}
func createBomb () {
bomb.removeFromParent()
var randomX = Int(arc4random_uniform(600))
var randomXCG = CGFloat(randomX)
bomb.size.height = playerSprite.size.height/2
bomb.size.width = bomb.size.height
bomb.position = CGPoint(x: randomXCG, y: self.size.height - bomb.size.height/2)
bomb.physicsBody = SKPhysicsBody(circleOfRadius: bomb.size.width / 2)
bomb.physicsBody?.dynamic = true
bomb.physicsBody?.allowsRotation = false
bomb.physicsBody?.restitution = 0.0
bomb.physicsBody?.friction = 10.0
bomb.physicsBody?.angularDamping = 0.0
bomb.physicsBody?.linearDamping = 0.0
bomb.physicsBody?.affectedByGravity = true
bomb.physicsBody?.categoryBitMask = CollisionCategoryBitmask.bomb
bomb.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Floor
bomb.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Coin
addChild(bomb)
}
func dropEnemy () {
self.enemySprite.removeFromParent()
var wait2 = SKAction.waitForDuration(0.0)
var run2 = SKAction.runBlock {
self.enemySprite.physicsBody?.dynamic = true
self.enemySprite.physicsBody?.affectedByGravity = true
}
createEnemy()
self.runAction(SKAction.repeatActionForever(SKAction.sequence([wait2, run2])))
}
func createCoins () {
coinOnScreen = true
var randomX = Int(arc4random_uniform(600))
var randomXCG = CGFloat(randomX)
coinSprite.size.height = playerSprite.size.height/2
coinSprite.size.width = coinSprite.size.height
coinSprite.position = CGPoint(x: randomXCG, y: self.size.height - coinSprite.size.height/2)
coinSprite.physicsBody = SKPhysicsBody(circleOfRadius: coinSprite.size.width/2)
coinSprite.physicsBody?.dynamic = true
coinSprite.physicsBody?.affectedByGravity = true
coinSprite.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Coin
coinSprite.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Enemy | CollisionCategoryBitmask.bomb
coinSprite.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Floor
addChild(coinSprite)
}
func createJoyStick () {
joyStickSprite.setScale(0.9)
joyStickSprite.position = CGPoint(x: self.size.width/1.1, y: joyStickSprite.size.height)
joyStickSprite.name = "joyStick"
joyStickSprite.userInteractionEnabled = false
joyStickSprite.alpha = 0.0
leftButton.setScale(0.8)
leftButton.position = CGPoint (x: joyStickSprite.position.x - 30, y: joyStickSprite.size.height)
rightButton.setScale(0.8)
rightButton.position = CGPoint (x: joyStickSprite.position.x + 30 , y: joyStickSprite.size.height)
addChild(leftButton)
addChild(rightButton)
addChild(joyStickSprite)
}
func createJumpButton () {
jumpButton.position = CGPoint (x: 30, y: joyStickSprite.size.height)
jumpButton.setScale(0.6)
jumpButton.name = "jumpButton"
addChild(jumpButton)
}
func createFireButton () {
fireButton.position = CGPoint (x: 70, y: joyStickSprite.size.height-50)
fireButton.setScale(0.6)
fireButton.name = "fireButton"
addChild(fireButton)
}
func updateCoinPosition () {
coinSprite.position.x = coinSprite.position.x + destY*20
}
func didBeginContact(contact: SKPhysicsContact) {
let firstNode = contact.bodyA.node as! SKSpriteNode
let secondNode = contact.bodyB.node as! SKSpriteNode
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Player) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Enemy) {
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let scene = SecondScene(size: self.scene!.size)
scene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view!.presentScene(scene, transition: transition)
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Player) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.bomb) {
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)
let scene = SecondScene(size: self.scene!.size)
scene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view!.presentScene(scene, transition: transition)
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Player) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Coin) {
coinOnScreen = false
self.coinSprite.removeFromParent()
score += 5
scoreLabel.text = String("Score \(score)")
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Enemy) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Coin) {
groundExplosion()
coinSprite.removeFromParent()
coinOnScreen = false
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Coin) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.bomb) {
bomb.removeFromParent()
coinSprite.removeFromParent()
coinOnScreen = false
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.bomb) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Coin) {
bomb.removeFromParent()
coinSprite.removeFromParent()
coinOnScreen = false
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.Floor) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Coin) {
var wait5 = SKAction.waitForDuration(1.5)
var fadeOut = SKAction.fadeAlphaTo(0.2, duration: 0.3)
var fadeIn = SKAction.fadeAlphaTo(1.0, duration: 0.3)
coinSprite.runAction(SKAction.repeatAction(SKAction.sequence([ wait5, fadeOut, fadeIn, fadeOut, fadeIn, fadeOut, fadeIn ]), count: 1), completion : {
self.coinSprite.removeFromParent()
self.coinOnScreen = false
})
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.bullet) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.Enemy)
{
var bullet1 = contact.bodyA.node
score += 1
scoreLabel.text = String("Score \(score)")
bullet1!.removeFromParent()
enemySprite.removeFromParent()
dropEnemy()
}
if (contact.bodyA.categoryBitMask == CollisionCategoryBitmask.bullet) &&
(contact.bodyB.categoryBitMask == CollisionCategoryBitmask.bomb )
{
var bullet1 = contact.bodyA.node
var bombEnemy = contact.bodyB.node
score += 1
scoreLabel.text = String("Score \(score)")
bullet1!.removeFromParent()
bombEnemy?.removeFromParent()
}
}
func createFloor () {
floorSprite.position = CGPoint(x: self.size.width/2, y: 0)
floorSprite.setScale(0.50)
floorSprite.physicsBody = SKPhysicsBody(edgeFromPoint: CGPointMake( -self.size.width, floorSprite.size.height/2), toPoint: CGPointMake(self.size.width, floorSprite.size.height/2 ))
floorSprite.physicsBody?.dynamic = false
floorSprite.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Floor
floorSprite.physicsBody?.collisionBitMask = CollisionCategoryBitmask.Enemy
floorSprite.physicsBody?.contactTestBitMask = CollisionCategoryBitmask.Enemy | CollisionCategoryBitmask.Coin
addChild(floorSprite)
}
override func update(currentTime: CFTimeInterval) {
//detect where on joystick player is touching
if left == true {
playerSprite.texture = SKTexture(imageNamed: "alienPink_swim3")
movePlayerLeft()
}
if right == true {
movePlayerRight()
playerSprite.texture = SKTexture(imageNamed: "alienPink_swim1")
}
//move player to other side when going off screen
if playerSprite.position.x < -20.0 {
playerSprite.position = CGPoint(x: self.size.width + 20.0, y: playerSprite.position.y)
} else if (playerSprite.position.x > self.size.width + 20.0) {
playerSprite.position = CGPoint(x: -20.0, y: playerSprite.position.y)
}
if coinOnScreen == true {
//remove coin if off screen
if coinSprite.position.x < -20.0 || coinSprite.position.x > self.size.width + 20.0 {
self.coinSprite.removeFromParent()
coinOnScreen = false
}
}
//remove bullet if off screen
if bullet?.position.x < -20.0 || bullet?.position.x > self.size.width + 20.0 {
self.bullet?.removeFromParent()
}
if coinSprite.position.y < floorSprite.size.height {
updateCoinPosition()
}
}
}
有什么建议吗?