Search code examples
swiftsprite-kitspritegame-physics

Collision Player - Enemies (Shooting Game - Swift 4 -SpriteKit)


I'm working on a Shooter Game coded in Swift 4, using SKSpriteNodes.

I've tried to make my game stop when an enemy, and to show the GameOverScene, but it does not work, and I don't understand why.

I've used the same kind of functions for the collision of the projectiles and the enemies, and it works well.

Here's my code, from the GameScene :

struct PhysicsCategory {
    static let None      : UInt32 = 0
    static let All       : UInt32 = UInt32.max
    static let Monster   : UInt32 = 0b1       // 1
    static let Projectile: UInt32 = 0b10      // 2
    static let Player    : UInt32 = 0b01
}

override func didMove(to view: SKView) {
    player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5)
    player.zPosition = 2

    player.physicsBody = SKPhysicsBody(rectangleOf: player.size) // 1
    player.physicsBody?.isDynamic = true // 2
    player.physicsBody?.categoryBitMask = PhysicsCategory.Monster // 3
    player.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4
    player.physicsBody?.collisionBitMask = PhysicsCategory.None // 5

    addChild(player) 
}

    func addMonster() {

    // Create sprite
    let monster = SKSpriteNode(imageNamed: "monster")
    monster.zPosition = 2

    monster.physicsBody = SKPhysicsBody(rectangleOf: monster.size) // 1
    monster.physicsBody?.isDynamic = true // 2
    monster.physicsBody?.categoryBitMask = PhysicsCategory.Monster // 3
    monster.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4
    monster.physicsBody?.collisionBitMask = PhysicsCategory.None // 5

    // Determine where to spawn the monster along the Y axis
    let actualY = random(min: monster.size.height/2, max: size.height - monster.size.height/2)

    // Position the monster slightly off-screen along the right edge,
    // and along a random position along the Y axis as calculated above
    monster.position = CGPoint(x: size.width + monster.size.width/2, y: actualY)

    // Add the monster to the scene
    addChild(monster)

    // vitesse augmentée
    let actualDuration = random(min: CGFloat(1), max: CGFloat(4))

     // Create the actions
    let actionMove = SKAction.move(to: CGPoint(x: -monster.size.width/2, y: actualY), duration: TimeInterval(actualDuration))
    let actionMoveDone = SKAction.removeFromParent()

    monster.run(SKAction.sequence([ actionMove, actionMoveDone]))
}

    func ennemyCollidesWithPlayer(monster: SKSpriteNode, player: SKSpriteNode){
    print("Game Over")

    let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
    let gameOverScene = GameOverScene(size: self.size, won: false)
    self.view?.presentScene(gameOverScene, transition: reveal)
}

func didBegin(_ contact: SKPhysicsContact) {
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    //collision player et enemy
    if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) &&
        (secondBody.categoryBitMask & PhysicsCategory.Player != 0)) {
        if let player = firstBody.node as? SKSpriteNode, let
            monster = secondBody.node as? SKSpriteNode {
            ennemyCollidesWithPlayer(monster: monster, player: player)
        }
    }
}

Solution

  • categoryBitMask is the classification of the physics body on the current object it also the identifier used when checking the type of physics body

    contactBitMask is setting the which objects will report in didBegin upon contact

    both your player and monster have the same categoryBitMask set

    change player to type PhysicsCategory.Player

    you will also need to set the player contactBitMask to

    contactTestBitMask = PhysicsCategory.Monster