sprite-kitswift2xcode7skspritenodeskphysicsbody

My Physics Contacts are not making contact in SpriteKit


I am using Xcode 7.3.1, iOS 9.3 and Swift 2. Also tested on simulator and my iPad directly. I have done numerous searches, read 2 books of Spritekit Physics and watched numerous video tutorial as well as written ones. I have written body physics with no problems before, and numerous times with smaller projects but this one is just giving me no feedback. This question has been posed here before in specific instances, i.e. 2 collisions with same spritenode or what is the difference between collisionBitMask and contactTestBitMask. I am aware of the differences and also aware that each object you wish to be in contact needs a categoryBitMask.

First, I have assigned a global Physicsbody struct (tried straight binary bitMask and the corresponding Int32 corresponding to each with no success with either), a physics delegate and each SKSpritenode corresponds with its paired contact/s. I have tried numerous ways to implement didBeginContact (regarding the way it is structured), none have made a difference over the other.

Earlier I mentioned feedback. I have eliminated all but my main player, bullets, newEnemy and enemyFire. When I try to even print a result of contact or collision to the console, it is like it does not even get read. I get no activity. These spritenodes are all within 1 class (GameScene), I have tried separate classes for each functional spritenode with no luck. Also, with separate classes, it seems to make things worse, even with protocols in place for communicating between classes and sub-classes. Which using separate classes is still new to me, eventhough I know it is the preferred way. I will show only the code I believe may need to be seen to minimize but let me know if there is anything else that needs to be seen. I simply want the bullets to hit the planes and I can go from there to my other objects.

import AVFoundation
import SpriteKit
import GameKit

// Binary connections for collision and colliding
struct PhysicsCategory {
    static let GroundMask : UInt32 = 1    //0x1 << 0
    static let BulletMask : UInt32 = 2    //0x1 << 1
    static let PlayerMask : UInt32 = 4    //0x1 << 2
    static let EnemyMask  : UInt32 = 8    //0x1 << 3
    static let EnemyFire  : UInt32 = 16   //0x1 << 4
    static let All        : UInt32 = UInt32.max // all nodes
}

class GameScene: SKScene, SKPhysicsContactDelegate {

    // Starting scene, passed to didMoveToView
    func startScene() {
    
        // Sets the physics delegate and physics body
        view?.showsPhysics = true
        self.physicsWorld.gravity = CGVectorMake(0, 0)
        self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        self.physicsWorld.contactDelegate = self // Physics delegate set
    }

    func setupPlayer() {
    
        player = SKScene(fileNamed: "Player")!.childNodeWithName("player")! as! SKSpriteNode

        // Body physics for player's planes
        player.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "MyFokker2.png"), size: player.size)
        player.physicsBody?.dynamic = false
        player.physicsBody?.usesPreciseCollisionDetection = true
        player.physicsBody?.categoryBitMask = PhysicsCategory.PlayerMask
        player.physicsBody?.contactTestBitMask = PhysicsCategory.EnemyFire
        player.physicsBody?.collisionBitMask = 0
    
        player.removeFromParent()
        self.addChild(player) // Add our player to the scene
    }

    // Create the ammo for our plane to fire
    func fireBullets() {
    
        bullet = SKSpriteNode(imageNamed: "fireBullet")
    
        // Body physics for plane's bulets
        bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
        bullet.physicsBody?.dynamic = false
        bullet.physicsBody?.usesPreciseCollisionDetection = true
        bullet.physicsBody?.categoryBitMask = PhysicsCategory.BulletMask
        bullet.physicsBody?.contactTestBitMask = PhysicsCategory.EnemyMask
        bullet.physicsBody?.collisionBitMask = 0
    
        self.addChild(bullet) // Add bullet to the scene
    }

    func spawnEnemyPlanes() {
        let enemy1 = SKScene(fileNamed: "Enemy1")!.childNodeWithName("enemy1")! as! SKSpriteNode
        let enemy2 = SKScene(fileNamed: "Enemy2")!.childNodeWithName("enemy2")! as! SKSpriteNode
        let enemy3 = SKScene(fileNamed: "Enemy3")!.childNodeWithName("enemy3")! as! SKSpriteNode
        let enemy4 = SKScene(fileNamed: "Enemy4")!.childNodeWithName("enemy4")! as! SKSpriteNode
    
        enemyPlanes = [enemy1, enemy2, enemy3, enemy4]
    
        // Generate a random index
        let randomIndex = Int(arc4random_uniform(UInt32(enemyPlanes.count)))
    
        // Get a random enemy
        newEnemy = (enemyPlanes[randomIndex])

        // Added randomEnemy's physics
        newEnemy.physicsBody = SKPhysicsBody(rectangleOfSize: newEnemy.size)
        newEnemy.physicsBody?.dynamic = false
        newEnemy.physicsBody?.usesPreciseCollisionDetection = true
        newEnemy.physicsBody?.categoryBitMask = PhysicsCategory.EnemyMask
        newEnemy.physicsBody?.contactTestBitMask = PhysicsCategory.BulletMask
        newEnemy.physicsBody?.collisionBitMask = 0
        
        newEnemy.removeFromParent()
        self.addChild(newEnemy)
    }

    func spawnEnemyFire() {
    
        enemyFire = SKScene(fileNamed: "EnemyFire")!.childNodeWithName("bullet")! as! SKSpriteNode
    
        enemyFire.removeFromParent()
        self.addChild(enemyFire) // Generate enemy fire
    
        // Added enemy's fire physics
        enemyFire.physicsBody = SKPhysicsBody(rectangleOfSize: enemyFire.size)
        enemyFire.physicsBody?.dynamic = false
        enemyFire.physicsBody?.usesPreciseCollisionDetection = true
        enemyFire.physicsBody?.categoryBitMask = PhysicsCategory.EnemyFire
        enemyFire.physicsBody?.contactTestBitMask = PhysicsCategory.PlayerMask
        enemyFire.physicsBody?.collisionBitMask = 0
    }

    func didBeginContact(contact: SKPhysicsContact) {
    
        if !self.gamePaused && !self.gameOver {
        
            // beginContact constants
            firstBody = contact.bodyA
            secondBody = contact.bodyB
        
            if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {    
                firstBody = contact.bodyA
                secondBody = contact.bodyB
            } else {   
                firstBody = contact.bodyB
                secondBody = contact.bodyA
            }

            // Contact statements
            if ((firstBody.categoryBitMask & PhysicsCategory.BulletMask != 0) && (secondBody.categoryBitMask & PhysicsCategory.EnemyMask != 0)) {   
                print("Bullet hit Enemy")
            }
            else if ((firstBody.categoryBitMask & PhysicsCategory.PlayerMask != 0) && (secondBody.categoryBitMask & PhysicsCategory.EnemyFire != 0)) {
                print("EnemyFire hit our Player")
            }
        }
    }
}

I tried to leave out the obvious code yet leave the code that would need to be know...sorry if it is lengthy. I have also tried checkPhysics functions as well and they cannot even recognize my objects. All SpriteNodes are passed to the didMoveToView function. Can anyone see what is wrong or have a reason why I am getting no contact at all?


Solution

  • The problem you are having is because all of your physics bodies are non-dynamic. Means their dynamic property is set to false. didBeginContact method will be called only if at least one of bodies is dynamic.

    From the docs:

    The dynamic property determines whether the body is simulated by the physics subsystem.

    So non-dynamic bodies are certainly excluded from simulation. I can't find if there is somewhere documented that this applies to contacts, but from my experience, I am pretty positive that contacts won't work between two static bodies.