SpriteKit碰撞检测无法正常工作

时间:2018-01-02 03:15:19

标签: ios swift sprite-kit

我的游戏中有三个节点 -

播放器 -

这是一艘你用操纵杆拖动的船。

let collisionPlayer : UInt32 = 0x1 << 1

let apple = SKSpriteNode(texture: texture)
    apple.position = position
    apple.physicsBody = SKPhysicsBody(circleOfRadius: apple.size.width / 2.0)
    apple.physicsBody?.affectedByGravity = false
    apple.physicsBody?.isDynamic = true
    apple.setScale(0.1)
    addChild(apple)

(“苹果”是船)

The Enemy Boat -

这是一艘随机跟随玩家的CPU船。

 let collisionNPC : UInt32 = 0x1 << 0


 appleNPC.position = position
    appleNPC.physicsBody = SKPhysicsBody(circleOfRadius: appleNPC.size.width / 2.0)
    appleNPC.physicsBody?.isDynamic = true
    appleNPC.physicsBody?.affectedByGravity = false
    appleNPC.position = CGPoint(x: 600, y: 200)

    appleNPC.setScale(0.1)
    addChild(appleNPC)

子弹 (言自明)

let collisionBullet : UInt32 = 0x1 << 2

(以下代码在TouchesEnded中)

  bullet?.name = "Bullet"
    bullet?.position = (appleNode?.position)!
    bullet?.setScale(0.05)
    bullet?.zPosition = 1
    bullet?.physicsBody = SKPhysicsBody(circleOfRadius: (bullet?.size.width)!/2)
    bullet?.physicsBody?.isDynamic = true
    bullet?.physicsBody?.affectedByGravity = false
    bullet?.physicsBody?.usesPreciseCollisionDetection = true

要移动子弹我使用代码:

    // Your code with delay
    if bulletNumbers > 0 {
        let offset = CGPoint(x: touchLocation.x - (bullet?.position.x)! , y: touchLocation.y - (bullet?.position.y)!)

        //Stops Bullet from shooting backwards


        //Get the direction of where to shoot
        let direction = offset

        //Make it shoot far enough to be guaranteed off screen
        let shootAmount = CGPoint(x: direction.x * 10, y: direction.y * 10)

        //Add the shoot amount to the current position
        let realDest = CGPoint(x: shootAmount.x + (bullet?.position.x)!, y: shootAmount.y + (bullet?.position.y)!)

        //Create the actions
        addChild(bullet!)
        self.bulletNumbers -= 1

        let distance = sqrt(pow(realDest.x - (appleNode?.position.x)!, 2) +
            pow(realDest.y - (appleNode?.position.y)!, 2))

        // run the sequence of actions for the firing
        let duration = TimeInterval(distance / PlayerMissileSpeed)
        let missileMoveAction = SKAction.move(to: realDest, duration: duration)
        let when = DispatchTime.now() + 10 // change 2 to desired number of seconds
        DispatchQueue.main.asyncAfter(deadline: when) { self.bulletNumbers += 1
        }
        bullet?.run(missileMoveAction) {
        self.bullet?.isHidden = true
        self.bullet?.removeFromParent()
        print("\(self.bulletNumbers)")
        }}
    else if bulletNumbers <= 0 {
      print("reload")

        let when = DispatchTime.now() + 2 // change 2 to desired number of seconds
        DispatchQueue.main.asyncAfter(deadline: when) {

        }

    }


}

func didBegin(_ contact: SKPhysicsContact) {
    print("test")


}

func setRandomStickColor() {
    let randomColor = UIColor.random()
    moveAnalogStick.stick.color = randomColor
}

func setRandomSubstrateColor() {
    let randomColor = UIColor.random()
    moveAnalogStick.substrate.color = randomColor
}

override func update(_ currentTime: TimeInterval) {
    /* Called before each frame is rendered */
    super.update(currentTime)
    let _:UInt32 = arc4random_uniform(1) //

    appleNodeCpuSpeed = CGFloat(1)


    var locationx : CGFloat
    var locationy: CGFloat

    locationx = (appleNode?.position.x)!
    locationy = (appleNode?.position.y)!
    let dx = locationx - (appleNodeNPC?.position.x)!
    let dy = locationy - (appleNodeNPC?.position.y)!
    let angle = atan2(dy, dx)
    let vx = cos(angle) * appleNodeCpuSpeed
    let vy = sin(angle) * appleNodeCpuSpeed


    self.appleNodeNPC?.position.x += vx
    self.appleNodeNPC?.position.y += vy

    let when = DispatchTime.now() + 0.25 // change 2 to desired number of seconds
    DispatchQueue.main.asyncAfter(deadline: when) {

          self.appleNodeNPC?.zRotation = angle + 90

    }
    //2

这很好用。子弹从船上发射到触摸位置,然而,当我试图引入碰撞时,事情开始出错。以下是我的代码:

 appleNode?.physicsBody?.categoryBitMask = collisionPlayer
    appleNode?.physicsBody?.collisionBitMask = collisionNPC
    appleNode?.physicsBody?.contactTestBitMask = 0

    appleNodeNPC?.physicsBody?.categoryBitMask = collisionNPC
    appleNodeNPC?.physicsBody?.collisionBitMask = collisionPlayer
    appleNodeNPC?.physicsBody?.contactTestBitMask = collisionBullet

    bullet?.physicsBody?.categoryBitMask = collisionBullet
    bullet?.physicsBody?.collisionBitMask = 0
    bullet?.physicsBody?.contactTestBitMask = collisionNPC


    physicsWorld.contactDelegate = self
    view.showsPhysics = true

然后在我的didBegin函数中我有:

func didBegin(_ contact: SKPhysicsContact) {
    print("test")


}

让我们从头开始。我点击屏幕,发射子弹。子弹不会与玩家碰撞,这是我最初想要的。然而,当子弹与敌舰接触时,它会发生碰撞。它环绕着船只并继续前往其原始目的地。我希望子弹与船只联系而不是其他任何东西 - 没有碰撞。我希望假设我的错误是因为我移动子弹的代码,但我不确定。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

  1. 定义唯一类别,确保您的课程为SKPhysicsContactDelegate,并让自己成为物理联系代表:
  2. //Physics categories

    let appleCategory:   UInt32 = 1 << 0
    let enemyCategory:    UInt32 = 1 << 1
    let bulletCategory:   UInt32 = 1 << 2
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
       physicsWorld.contactDelegate = self
    
    1. 分配类别(通常在didMove(to view:)

      apple.physicsBody.catgeoryBitMask = appleCategory enemy.physicsBody.catgeoryBitMask = enemyCategory bullet.physicsBody.catgeoryBitMask = bulletCategory

    2. (确保您已为每个节点创建了物理实体)

      1. 设置碰撞:
      2. apple.physicsBody?.collisionBitMask = 0 // apple/player collides with nothing enemy.physicsBody?.collisionBitMask = 0 // enemy collides with nothing bullet.physicsBody?.collisionBitMask = 0 // bullet collides with nothing

        甚至:

        for node in [apple, enemy, bullet] {
           node.physicsBody?.collisionBitMask = 0 //  collides with nothing
           }
        
        1. 设置联系人

          bullet.physicsBody?.collisionBitMask = enemyCategory // bullet contacts enemy

        2. 确保每个潜在联系人中涉及的至少一个对象的物理主体上的isDynamic属性设置为true,否则将不会生成任何联系人。两个对象都没有必要是动态的。

          当子弹和敌人接触时,你现在应该被didBegin召唤。您可以像这样编码didBegin

            func didBegin(_ contact: SKPhysicsContact) {
               print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")
          
               let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
          
               switch contactMask {
               case bulletCategory | enemyCategory:
                  print("bullet and enemy have contacted.")
                  let bulletNode = contact.bodyA.categoryBitMask == bulletCategory ? contact.bodyA.node : contact.bodyB.node
                  enemyHealth -= 10
                  bulletNode.removeFromParent
               default:
                  print("Some other contact occurred")
               }
          

          }