fatal error: unexpectedly found nil while unwrapping an Optional value for physics body contact - ios

I can't seem to figure out which optional value it is talking about or why i am getting this error. I checked my score integer and made sure that I declared its value is 0 until it makes contact with the enemy. In the simulator the counter counts the first 4 or 5 enemies then crashes.
var score = Int? ()
var scoreLabel = UILabel ()
override func didMoveToView(view: SKView) {
scoreLabel.text = "\(score)"
scoreLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height:
20))
scoreLabel.textColor = UIColor.blackColor()
score = nil
if score == nil {
score = 0
scoreLabel.text = "\(score!)"
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == PhysicsCategory.bullet) &&
(secondBody.categoryBitMask == PhysicsCategory.enemy) ||
(firstBody.categoryBitMask == PhysicsCategory.enemy) &&
(secondBody.categoryBitMask == PhysicsCategory.bullet)) {
//i get the error next line
collisionWithBullet((firstBody.node as! SKSpriteNode),
bullet: (secondBody.node as! SKSpriteNode))
}
}
func collisionWithBullet(enemy: SKSpriteNode, bullet: SKSpriteNode){
score? += 1
scoreLabel.text = "\(score!)"
enemy.removeFromParent ()
bullet.removeFromParent ()
}

Change score to
var score = 0
instead of
var score = Int? ()
and instead of this part
score = nil
if score == nil {
score = 0
scoreLabel.text = "\(score!)"
}
write only this
scoreLabel.text = "\(score)"
Edit:
instead of this part
collisionWithBullet((firstBody.node as! SKSpriteNode),
bullet: (secondBody.node as! SKSpriteNode))
do something like this
if let firstNode = firstBody.node as? SKSpriteNode,
secondNode = secondBody .node as? SKSpriteNode {
collisionWithBullet((firstNode),
bullet: (secondNode))
}

Related

How to add levels to Flappybird like game?

This might be bit confusing.
This is my override function ATM, where my walls are spawning every 2 seconds.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameStarted == false{
gameStarted = true
mexican.physicsBody?.affectedByGravity = true
let spawn = SKAction.run({
() in
self.createWalls()
})
let delay = SKAction.wait(forDuration: 2.0)
let spawnDelay = SKAction.sequence([delay, spawn])
let spawnDelayForever = SKAction.repeatForever(spawnDelay)
self.run(spawnDelayForever)
let distance = CGFloat(self.frame.width + wallPair.frame.width)
let movePipes = SKAction.moveBy(x: -distance - 50, y: 0, duration: TimeInterval( 0.01 * distance))
let removePipes = SKAction.removeFromParent()
moveAndRemove = SKAction.sequence([movePipes,removePipes])
mexican.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
mexican.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 65))
I have found a tutorial where the wall spawn duration is made faster but I am unsure how to incorporate this into my code as they have used a new function.
My walls are being spawned in the override function which makes it hard for me to call this when adding my if statement.
func startNewLevel(){
levelNumber += 1
if self.actionForKey("spawningEnemies") != nil{
self.removeActionForKey("spawningEnemies")
}
var levelDuration = timeInterval()
switch levelNumber {
case 1: levelDuration = 2.0
case 2: levelDuration = 1.8
case 3: levelDuration = 1.6
default: levelDuration = 0.5
print("Cannot find level into")
}
let spawn = SKAction.run(spawnEnemy)
let waitToSpawn = SKAction.waitForDuration(levelDuration)
let spawnSequence = SKAction.sequence([waitToSpawn, spawn])
let spawnForever = SKAction.repeatActionForever(spawnSequence)
self.runAction(spawnForever, withKey: "spawningEnemies")
This is where I would be calling the function startNewLevel() but my wall spawning is set up in override func touchedBegan.
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCategory.bird && secondBody.categoryBitMask == physicsCategory.wall{
score += 1
scoreLabel.text = "\(score)"
firstBody.node?.removeFromParent()
if score == 10 || score == 15 || score == 20{
startNewLevel()
if score > UserDefaults().integer(forKey: "HIGHSCORE") {
saveHighScore()
}
}
else if firstBody.categoryBitMask == physicsCategory.bird && secondBody.categoryBitMask == physicsCategory.wall{
score += 1
scoreLabel.text = "\(score)"
secondBody.node?.removeFromParent()
if score > UserDefaults().integer(forKey: "HIGHSCORE") {
saveHighScore()
}
}
This is probably really confusing but if anyone gets me HOLA you will be my favourite person on the earth.

Collide type source error - spritekit swift game

So I have adjusted my games ball type from a shape to an image which forced me to redo the physics of my game. I am new to swift and have struggled with fixing my collisions in my swift game.
class GameScene: SKScene, GameDelegate, SKPhysicsContactDelegate {
var ball: Ball!
let ballSpeedX = CGFloat(500)
//ball = Ball(imageNamed:"colorBall.png")
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
// board
let boards = Boards.make(CollideType.BoardStart.rawValue)
var lastBoard: SKNode?
var boardSpeedY: CGFloat { get { return CGFloat(160) * accelerate }}
let boardDistanceY = CGFloat(300)
let boardYDistanceHide = CGFloat(30)
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
let flooeBody = SKPhysicsBody.init(edgeLoopFromRect: self.frame)
self.physicsBody = floorBody
self.physicsBody!.affectedByGravity = false
self.physicsBody!.usesPreciseCollisionDetection = true
self.physicsBody!.dynamic = true
self.physicsBody!.mass = 0
self.physicsBody!.friction = 0
self.physicsBody!.linearDamping = 0
self.physicsBody!.angularDamping = 0
self.physicsBody!.restitution = 1
self.physicsBody!.categoryBitMask = CollisionTypes.Floor.rawValue
self.physicsBody!.contactTestBitMask = CollisionTypes.Ball.rawValue
// Prepare the ball - physics engine.
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.width/2)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody!.restitution = 0.8
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.friction = 0.3
ball.physicsBody!.dynamic = true
ball.physicsBody!.mass = 0.5
ball.physicsBody!.allowsRotation = true
ball.physicsBody!.categoryBitMask = CollisionTypes.Ball.rawValue
ball.physicsBody!.contactTestBitMask = CollisionTypes.Floor.rawValue
ball.physicsBody!.collisionBitMask = CollisionTypes.Floor.rawValue
ball.hidden = false
self.addChild(ball)
// scene
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.categoryBitMask = CollideType.Scene.toMask()
self.physicsBody!.dynamic = false
self.physicsBody!.friction = 0
// ceil
let ceil = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
ceil.position.x = CGRectGetMidX(self.frame)
ceil.position.y = self.frame.height - CGRectGetMidY(ceil.frame)
ceil.physicsBody = SKPhysicsBody(rectangleOfSize: ceil.frame.size)
ceil.physicsBody!.categoryBitMask = CollideType.Ceil.toMask()
ceil.physicsBody!.dynamic = false
ceil.alpha = 0
self.addChild(ceil)
// floor
let floor = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
floor.position.x = CGRectGetMidX(self.frame)
floor.position.y = CGRectGetMidY(floor.frame)
floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.frame.size)
//floor.physicsBody!.categoryBitMask = CollideType.Floor.toMask() two
floor.physicsBody!.dynamic = false
floor.alpha = 0
self.addChild(floor)
}
That is the scene and physics I attempted to set up and was directed with. Below is the collide errors which cause the app to crash upon touch.
func didBeginContact(contact: SKPhysicsContact) {
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board error: CANNOT CONVERT VALUE OF TYPE BOOL TO EXPCTD ARG TYPE UIINT32
if bitMaskAAndB | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didBeginContact(boardNode, ball: ball, contact: contact, game: self)
}
// ball and ceil => ERROR
else if bitMaskAAndB == CollideType.toMask([.Ball, .Ceil]) {
stopGame()
}
// ball and floor => stop game
else if bitMaskAAndB == CollideType.toMask([.Ball, .Floor]) {
stopGame()
}
}
func didEndContact(contact: SKPhysicsContact) {
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board, handle it by board delegate
if contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didEndContact(boardNode, ball: ball, contact: contact, game: self)
}
}
CollideType definition as below:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
So the issue now is that you have two definition for your masks:
Remove this one:
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
Use only this one:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
Correct all code to match with CollideType definitions.
Correct this line in didBeginContact:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
with:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollideType.Floor.toMask() ? contact.bodyB.categoryBitMask : CollideType.Ball.toMask()
If you have correct all you will don't have yet this error:
// ball and ceil => ERROR

Simplifying collision and player death in SpriteKit

I want to add a bunch of different rocks and other dangerous objects that the player can collide with and die. How would I do this effectively? Now if I would copy paste these functions, it would surely work. But it seems like a huge amount of unnecessary code.
Sidenote: I'm very new to xcode, swift 2 & Sprite-kit.
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == PhysicsCategory.Rock) && (secondBody.categoryBitMask == PhysicsCategory.Bullet) || (firstBody.categoryBitMask == PhysicsCategory.Bullet) && (secondBody.categoryBitMask == PhysicsCategory.Rock)) {
CollisionWithBullet(firstBody.node as! SKSpriteNode, Bullet: secondBody.node as! SKSpriteNode)
}
if ((firstBody.categoryBitMask == PhysicsCategory.Rock) && (secondBody.categoryBitMask == PhysicsCategory.Player) || (firstBody.categoryBitMask == PhysicsCategory.Player) && (secondBody.categoryBitMask == PhysicsCategory.Rock)) {
CollisionWithPlayer(firstBody.node as! SKSpriteNode, Player: secondBody.node as! SKSpriteNode)
}
}
func CollisionWithPlayer(Rock: SKSpriteNode, Player: SKSpriteNode){
let ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
if (HighscoreDefault.valueForKey("Highscore") != nil){
Highscore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
} else {
Highscore = 0
}
if (Score > Highscore){
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
}
self.view?.presentScene(EndScene())
ScoreLabel.removeFromSuperview()
}
So what you're likely looking for here is the bitwise OR operator and the bitwise AND operator.
With SpriteKit, physicsBodies can have multiple categories assigned to them. For instance, if we have the following categories set up:
enum CollisionCategories : UInt32 {
case Player = 1
case Enemy = 2
case Rock = 4
case Bullet = 8
}
we can set up the player category and contact bitmasks as follows:
let player = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 50, height: 50))
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.categoryBitMask = CollisionCategories.Player.rawValue
player.physicsBody?.contactTestBitMask = CollisionCategories.Enemy.rawValue
and two enemy category and contact bitmasks as follows:
let rockEnemy = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: 25, height: 25))
rockEnemy.physicsBody = SKPhysicsBody(rectangleOfSize: rockEnemy.size)
rockEnemy.physicsBody?.categoryBitMask = CollisionCategories.Enemy.rawValue | CollisionCategories.Rock.rawValue
rockEnemy.physicsBody?.contactTestBitMask = CollisionCategories.Player.rawValue
let bulletEnemy = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 25, height: 25))
bulletEnemy.physicsBody = SKPhysicsBody(rectangleOfSize: bulletEnemy.size)
bulletEnemy.physicsBody?.categoryBitMask = CollisionCategories.Enemy.rawValue | CollisionCategories.Bullet.rawValue
bulletEnemy.physicsBody?.contactTestBitMask = CollisionCategories.Player.rawValue
Notice that on setting the category bitmasks, I am using the bitwise OR operator ('|'). This is a nice way of setting the bitmasks to two different categories at the same time. This way, a sprite can be both a rock and an enemy or a bullet and an enemy, etc.
See the image below for an idea of what is happening bitwise under the hood.
In our contact detection function, we can use the bitwise AND operator ('&') to see if our contact possesses a certain category.
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if (firstBody.categoryBitMask & CollisionCategories.Player.rawValue == CollisionCategories.Player.rawValue &&
secondBody.categoryBitMask & CollisionCategories.Enemy.rawValue == CollisionCategories.Enemy.rawValue) {
print("The collision was between the Player and an Enemy")
}
else if (firstBody.categoryBitMask & CollisionCategories.Enemy.rawValue == CollisionCategories.Enemy.rawValue &&
secondBody.categoryBitMask & CollisionCategories.Player.rawValue == CollisionCategories.Player.rawValue) {
print("The collision was between the Player and an Enemy")
}
}
This way, you can have enemies with multiple categories, but you can always do one check to see if a node is in fact an enemy, regardless of what other categories they might possess.

didBeginContact for three sprites works for 2 sprites, but not for the third one - Swift2

I have a bird, multiple desks and a star. When the bird collides with one of the desks, the didBeginContact method works fine, but when it collides with the star, nothing happens. I will copy the code where I added some print statements so it is easier to see what is happening and then I will paste the print statements that it prints out.
Bird (just the initialization of the physicsBody part):
class Bird: SKSpriteNode {
var sc: SKScene!
init(sc: SKScene) {
let texture = SKTexture(imageNamed: "hero")
let size = texture.size()
self.sc = sc
super.init(texture: texture, color: UIColor.clearColor(), size: CGSizeMake(size.width/2, size.height/2))
self.zPosition = Layer.Bird.rawValue
self.name = "bird"
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2)
self.physicsBody?.categoryBitMask = PhysicsCategory.Bird
self.physicsBody?.collisionBitMask = PhysicsCategory.Desk
self.physicsBody?.contactTestBitMask = PhysicsCategory.Desk | PhysicsCategory.StarSpecial | PhysicsCategory.Star
self.physicsBody?.allowsRotation = true
self.physicsBody?.restitution = 0
self.physicsBody?.usesPreciseCollisionDetection = true
}
// other methods and the required init
}
The star class is constructed the same way so I will just copy physicsBody related code:
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2, center: self.position)
self.physicsBody?.affectedByGravity = false
self.physicsBody?.pinned = true
self.physicsBody?.categoryBitMask = PhysicsCategory.StarSpecial
self.physicsBody?.collisionBitMask = PhysicsCategory.None
self.physicsBody?.contactTestBitMask = PhysicsCategory.Bird
self.physicsBody?.usesPreciseCollisionDetection = true
self.physicsBody?.allowsRotation = false
self.physicsBody?.restitution = 0
self.physicsBody?.usesPreciseCollisionDetection = true
And the didBeginContact method in GameScene:
func didBeginContact(contact: SKPhysicsContact) {
print("something has collided")
if contact.bodyA.categoryBitMask == PhysicsCategory.Bird && contact.bodyB.categoryBitMask == PhysicsCategory.Desk {
birdSprite.BirdDidCollideWithDesk(contact.bodyA.node as! Bird, desk: contact.bodyB.node as! Desk, scoreClass: scoreClass, scoreLabel: scoreLabel)
print("bird and desk have collided")
} else if contact.bodyA.categoryBitMask == PhysicsCategory.Desk && contact.bodyB.categoryBitMask == PhysicsCategory.Bird {
print("desk and bird have collided")
birdSprite.BirdDidCollideWithDesk(contact.bodyB.node as! Bird, desk: contact.bodyA.node as! Desk, scoreClass: scoreClass, scoreLabel: scoreLabel)
}
if contact.bodyA.categoryBitMask == PhysicsCategory.Bird && contact.bodyB.categoryBitMask == PhysicsCategory.StarSpecial {
print("collided into star1")
starSpecial.removeStar(contact.bodyB.node as! Star)
} else if contact.bodyA.categoryBitMask == PhysicsCategory.StarSpecial && contact.bodyB.categoryBitMask == PhysicsCategory.Bird {
print("collided into star2")
starSpecial.removeStar(contact.bodyB.node as! Star)
}
}
If I run it, I get the following messages:
If the bird collides with a desk: "something has collided", "desk and bird have collided"
If the bird collides with the star: "something has collided"
Neither of second two conditions is met, so the message "collided into star1" or "collided into star2" is not printed out.
Any idea what could be causing this?

Collisions between sprites in SpriteKit

I'm making a game in XCode using SpriteKit. The game has a player and different types of projectiles that he has to avoid. When the player collides with the projectiles, the score changes and the projectile disappears. However, when two projectiles collide, they kind of bounce away.
I want to make that every time two projectiles collide, they act like nothing happened and they keep going in their original path. What should I do?
*Note: This is not the whole code, it's just what matters.
import SpriteKit
struct Physics {
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = SKSpriteNode(imageNamed: "p1.png")
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
player.position = CGPointMake(self.size.width/2, self.size.height/5)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.dynamic = false
player.physicsBody?.categoryBitMask = Physics.player
player.physicsBody?.collisionBitMask = Physics.missileOne
player.physicsBody?.collisionBitMask = Physics.missileTwo
var missileOneTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("SpawnMissileOne"), userInfo: nil, repeats: true)
var missileTwoTimer = NSTimer.scheduledTimerWithTimeInterval(1.2, target: self, selector: Selector("SpawnMissileTwo"), userInfo: nil, repeats: true)
self.addChild(player)
}
//When contact happens
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileOne)) {
CollisionWithMissileOne(firstBody.node as SKSpriteNode, missileOne: secondBody.node as SKSpriteNode)
} else if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileTwo)){
CollisionWithMissileTwo(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
} else if ((firstBody.categoryBitMask == Physics.missileOne)&&(secondBody.categoryBitMask == Physics.missileTwo)) {
CollisionBetweenMissiles(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
}
}
//For Player and MissileOne
func CollisionWithMissileOne(player: SKSpriteNode, missileOne: SKSpriteNode) {
missileOne.removeFromParent()
}
//For Player and MissileTwo
func CollisionWithMissileOne(player: SKSpriteNode, missileTwo: SKSpriteNode) {
missileTwo.removeFromParent()
}
//For MissileOne and MissileTwo
func CollisionBetweenMissiles(missileOne: SKSpriteNode, missileTwo: SKSpriteNode) {
???WHAT SHOULD I CODE HERE???
}
}
The confusion is that the collisionBitMask is used to define which physicsBodies that interacts in the physicsModel. What you really want is contactTestBitmask.
Also your Physics doesn't return proper values to use for a Bit Mask. As pure Ints they should be 1,2,4,8 etc.
Here is your code changed to something that (hopefully) works, I've commented changes wherever I've made them.
struct Physics {
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 4 // to work properly as bit masks
}
This change is necessary if you want to check for contact with more than one type of physicsBody.categoryBitMask. Check out the player.physicsBody?.contactTestBitMask = ... in didMoveToView:
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
// All your existing player-stuff is fine until...
// contactTest, not collision but contact, also: use bitwise OR
player.physicsBody?.contactTestBitMask = Physics.missileOne | Physics.missileTwo
self.addChild(player)
// It is not recommended to use NSTimer for SpriteKit, use SKActions instead
let missileOneWait = SKAction.waitForDuration(1)
let callSpawnOneAction = SKAction.runBlock({ self.spawnMissileOne() })
let missileOneRepeat = SKAction.repeatActionForever(SKAction.sequence([missileOneWait, callSpawnOneAction]))
runAction(missileOneRepeat)
let missileTwoWait = SKAction.waitForDuration(1.2)
let callSpawnTwoAction = SKAction.runBlock({ self.spawnMissileTwo() })
let missileTwoRepeat = SKAction.repeatActionForever(SKAction.sequence([missileTwoWait, callSpawnTwoAction]))
runAction(missileTwoRepeat)
}
Pretty much rewritten didBeginContact to something I believe reads and scales a lot better:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody = contact.bodyA
var secondBody = contact.bodyB
// Rewritten with dynamic variables
var playerNode : SKSpriteNode? {
if firstBody.categoryBitMask == Physics.player {
return firstBody.node as? SKSpriteNode
} else if secondBody.categoryBitMask == Physics.player {
return secondBody.node as? SKSpriteNode
}
return nil
}
// If you want to handle contact between missiles you need to split this
// into two different variables
var missileNode : SKSpriteNode? {
let bitmask1 = firstBody.categoryBitMask
let bitmask2 = secondBody.categoryBitMask
if bitmask1 == Physics.missileOne || bitmask1 == Physics.missileTwo {
return firstBody.node as? SKSpriteNode
} else if bitmask2 == Physics.missileOne || bitmask2 == Physics.missileTwo {
return secondBody.node as? SKSpriteNode
}
return nil
}
if playerNode != nil {
collisionBetweenPlayer(playerNode, missile: missileNode)
}
}
Then you'll only need one function for contact between missile and player:
func collisionBetweenPlayer(player: SKSpriteNode?, missile: SKSpriteNode?) {
missile?.removeFromParent()
}

Resources