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?
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.