0

I'm coding a simple game where the player must avoid obstacles as he plays, so I need to be able to check when the player makes contact with an obstacle. After following countless tutorials, I'm still not able to make it work. This is my code right now (I've taken out anything not relating to contact detection):

import SpriteKit

class GameScene: SKScene {
  
  struct PhysicsCategory {
    static let none      : UInt32 = 0
    static let all       : UInt32 = UInt32.max
    static let MrPig   : UInt32 = 0b1       // 1
    static let obstacle: UInt32 = 0b10      // 2
  }
  
  let airObstacles = ["spikeRectangle", "spikeSquare", "topSpikes", "bottomSpikes"]
  
  let mrPig = SKSpriteNode(imageNamed: "mrPig")
  
  var touching = false
  
  override func didMove(to view: SKView) {
    
    mrPig.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
    mrPig.physicsBody?.isDynamic = true
    mrPig.physicsBody?.categoryBitMask = PhysicsCategory.MrPig
    mrPig.physicsBody?.contactTestBitMask = PhysicsCategory.obstacle
    mrPig.physicsBody?.collisionBitMask = PhysicsCategory.none
    mrPig.physicsBody?.usesPreciseCollisionDetection = true
    
    mrPig.position = CGPoint(x: 100, y: 80)
    mrPig.zPosition = 2
    mrPig.setScale(0.2)
    addChild(mrPig)
    
    physicsWorld.gravity = .zero
    physicsWorld.contactDelegate = self
    
    run(SKAction.repeatForever(
      SKAction.sequence([
        SKAction.run(moveDown),
        SKAction.wait(forDuration: 0.1)
      ])
    ))
    
    run(SKAction.repeatForever(
      SKAction.sequence([
        SKAction.run(createObstacle),
        SKAction.wait(forDuration: TimeInterval(objectSpeed))
      ])
    ))
  }
  
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if touches.first != nil {
      touching = true
      mrPig.run(SKAction.moveTo(y: size.height - 20, duration: 0.8))
    }
  }
  
  override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if touches.first != nil {
      touching = false
    }
  }
  
  func moveDown() {
    if touching == false && mrPig.position.x > 80 {
      mrPig.run(SKAction.moveTo(y: 80, duration: 0.5))
    }
  }

  
  func createObstacle() {
    let airObstacle = SKSpriteNode(imageNamed: airObstacles.randomElement()!)
    
    airObstacle.physicsBody = SKPhysicsBody(rectangleOf: airObstacle.size) // 1
    airObstacle.physicsBody?.isDynamic = true // 2
    airObstacle.physicsBody?.categoryBitMask = PhysicsCategory.obstacle // 3
    airObstacle.physicsBody?.contactTestBitMask = PhysicsCategory.MrPig // 4
    airObstacle.physicsBody?.collisionBitMask = PhysicsCategory.none // 5

    airObstacle.position = CGPoint(x: size.width, y: 200)
    airObstacle.zPosition = 2
    addChild(airObstacle)
    let moveAirObstacle = SKAction.moveTo(x: 0, duration: 2)
    let moveAirObstacleDone = SKAction.removeFromParent()
    airObstacle.run(SKAction.sequence([moveAirObstacle, moveAirObstacleDone]))
    }
  }
}

extension GameScene: SKPhysicsContactDelegate {
  func didBegin(_ contact: SKPhysicsContact) {
    // 1
    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
    }
    
    // 2
    if ((firstBody.categoryBitMask & PhysicsCategory.obstacle != 0) &&
      (secondBody.categoryBitMask & PhysicsCategory.MrPig != 0)) {
      print("game over")
    }
  }
}

I'm relatively new to coding, and this is the first game I've ever made with swift. Any help would be much appreciated!

drew.ss
  • 3
  • 3
  • What do you mean by collision detection? When it comes to SpriteKit, collision and contact are two different physical phenomena. – El Tomato Jul 09 '20 at 23:25
  • My bad, I guess I meant contact detection. Thanks! – drew.ss Jul 09 '20 at 23:34
  • What's working so far? If you insert print("") inside didBegin, do you get a call? – El Tomato Jul 09 '20 at 23:43
  • nope, nothing prints. the did begin function isn't being called at all. – drew.ss Jul 10 '20 at 00:11
  • Setting up the contact bit mask and the collision bit mask can be quite confusing especially if you have a lot of characters involved in the game. I would try setting the contact bit mask of mrPig to 2, the contact bit mask of the obstacle to 0. – El Tomato Jul 10 '20 at 02:45
  • Wait... Have you added `SKPhysicsContactDelegate` to your game scene? – El Tomato Jul 10 '20 at 02:51

1 Answers1

0

Have a read of these previous answers:

My step-by-step guide for collisions and contacts: https://stackoverflow.com/a/51041474/1430420

And a guide to collision and contactTest bit masks: https://stackoverflow.com/a/40596890/1430420

Manipulating bit masks to turn individual collision and contacts off and on. https://stackoverflow.com/a/46495864/1430420

Steve Ives
  • 7,894
  • 3
  • 24
  • 55