1
votes

My Hero / Player instance can get destroyed by either touching an enemy instance or a enemyBullet instance. This is my enemy:

physicsBody = SKPhysicsBody(rectangleOfSize: size)
physicsBody?.categoryBitMask = PhysicsCategory.enemy
physicsBody?.collisionBitMask = 0
physicsBody?.contactTestBitMask = PhysicsCategory.bullet
physicsBody?.affectedByGravity = false
physicsBody?.allowsRotation = false
physicsBody?.dynamic = true

This is my enemyBullet:

bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
bullet.physicsBody?.categoryBitMask = PhysicsCategory.enemyBullet
bullet.physicsBody?.contactTestBitMask = PhysicsCategory.hero
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.dynamic = false

And this is my hero:

physicsBody = SKPhysicsBody(rectangleOfSize: size)
physicsBody?.affectedByGravity = false
physicsBody?.categoryBitMask = PhysicsCategory.hero
physicsBody?.contactTestBitMask = PhysicsCategory.enemy | PhysicsCategory.enemyBullet
physicsBody?.dynamic = false

My Player does properly contact with enemy instances, but does not contact with enemyBullets. Instead, there is a random SKPhysicsContact instantiated, when a enemy shoots. This is what my handling function looks like:

func didBeginContact(contact: SKPhysicsContact) {
        // Enemy + bullet
        if((contact.bodyA.categoryBitMask == PhysicsCategory.enemy && contact.bodyB.categoryBitMask == PhysicsCategory.bullet) || (contact.bodyA.categoryBitMask == PhysicsCategory.bullet && contact.bodyB.categoryBitMask == PhysicsCategory.enemy)) {
            // TODO
        }

        // Hero + enemy
        else if((contact.bodyA.categoryBitMask == PhysicsCategory.hero && contact.bodyB.categoryBitMask == PhysicsCategory.enemy) || (contact.bodyA.categoryBitMask == PhysicsCategory.enemy && contact.bodyB.categoryBitMask == PhysicsCategory.hero)) {
            print("HERO AND ENEMY")
        }

        // Hero + enemyBullet
        else if((contact.bodyA.categoryBitMask == PhysicsCategory.hero && contact.bodyB.categoryBitMask == PhysicsCategory.enemyBullet) || (contact.bodyA.categoryBitMask == PhysicsCategory.enemyBullet && contact.bodyB.categoryBitMask == PhysicsCategory.hero)) {
            print("HERO AND BULLET")
        }
        else {
            print("DEBUG: \(contact.bodyA.categoryBitMask) AND ˜\(contact.bodyB.categoryBitMask)")
        }
    }

So: What happens is that whenever an enemy shoots (shooting enemyBullet), it will run to the else in my handling function. This will print "DEBUG: 1 AND 6". 1 = enemy, 6 = enemyBullet.

Why should my enemy throw a contact when he shoots the bullet? How can i make my game detect when the hero is hit by enemyBullet?

EDIT: Thanks to @KnightOfDragon:

  1. When using the ContactBitMask and CategoryBitMask make sure to not simply set them to 1,2,3,4,etc. Set them to:

    static let environment: UInt32 = 0b00000000000000000000000000000001 static let powerup: UInt32 = 0b00000000000000000000000000000010 static let hero: UInt32 = 0b00000000000000000000000000100000 static let bullet: UInt32 = 0b00000000000000000000000001000000 static let enemy: UInt32 = 0b00000000000000000100000000000000 static let enemyBullet: UInt32 = 0b00000000000000001000000000000000

    static let enemyAndEnemyBullet: UInt32 = 0b00000000000000001100000000000000

  2. For the love of god: When using sprites where you expect contacts from aka SKPhysicsContact, always set them to dynamic = true. Otherwise it won't work.

1

1 Answers

2
votes

If you are using 6, then you are not using masks correctly. Mask values have to be represented in a power of 2, so that no bits overlay each other. By saying 6, you are saying 0110, so your enemy bullet can contact whatever 2 and 4 represent. Post your category enum so that I may complete this answer.

Edit

static let enemy: UInt32       = 0b00000000000000000000000000000001 
static let bullet: UInt32      = 0b00000000000000000000000000000010 
static let hero: UInt32        = 0b00000000000000000000000000000100 
static let environment: UInt32 = 0b00000000000000000000000000001000 
static let powerup: UInt32     = 0b00000000000000000000000000010000
static let enemyBullet: UInt32 = 0b00000000000000000000000000100000

Then, to make your code more readable, you can do things like

static let enemyAndEnemyBullet: UInt32 = 0b00000000000000000000000000100001
...
player.contactBitMask =  enemyAndEnemyBullet;
...

if((bodyA == player.categoryBitMask) && (bodyB.categoryBitMask | enemyAndEnemyBullet) > 0)
{
    ...
}

instead of using

player.contactBitMask =  enemy | enemyBullet;
...
if((bodyA == player.categoryBitMask) && (bodyB.categoryBitMask == enemy || bodyB == enemyBullet))
{
    ...
}

Now all the leading zeros are not needed, I did it this way so you can see how the mask works and what the max is. (32 different masks)