SpriteKit 碰撞检测无法正常工作

Ale*_*rie 1 ios sprite-kit swift

我的游戏中有三个节点 -

玩家-

这是一艘可以使用操纵杆拖动的船。

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)
Run Code Online (Sandbox Code Playgroud)

(“苹果”是船)

敌船——

这是一艘随机跟随玩家的 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)
Run Code Online (Sandbox Code Playgroud)

子弹 (不言自明)

let collisionBullet : UInt32 = 0x1 << 2
Run Code Online (Sandbox Code Playgroud)

(以下代码在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
Run Code Online (Sandbox Code Playgroud)

为了移动子弹,我使用代码:

    // 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
Run Code Online (Sandbox Code Playgroud)

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

 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
Run Code Online (Sandbox Code Playgroud)

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

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


}
Run Code Online (Sandbox Code Playgroud)

让我们从头开始。我点击屏幕,子弹就发射了。子弹不会与玩家碰撞,这正是我最初想要的。然而,当子弹与敌舰接触时,它确实会发生碰撞。它绕着船转,继续前往原来的目的地。我希望子弹能够接触到船,而不是其他任何东西 - 没有碰撞。我希望假设我的错误是由于我移动子弹的代码造成的,但我不确定。任何帮助表示赞赏。

Ste*_*ves 5

  1. 定义独特的类别,确保您的班级是 aSKPhysicsContactDelegate并使您自己成为物理接触代表:

//Physics categories

let appleCategory:   UInt32 = 1 << 0
let enemyCategory:    UInt32 = 1 << 1
let bulletCategory:   UInt32 = 1 << 2

class GameScene: SKScene, SKPhysicsContactDelegate {
   physicsWorld.contactDelegate = self
Run Code Online (Sandbox Code Playgroud)
  1. 分配类别(通常在didMove(to view:)

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

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

  1. 设置碰撞:

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
   }
Run Code Online (Sandbox Code Playgroud)
  1. 设置联系人

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

确保每个潜在接触中涉及的至少一个对象的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")
     }
Run Code Online (Sandbox Code Playgroud)

}

  • 我们需要建议 Stackoverflow 恢复文档,但要以某种方式标记特定主题的常见答案,以便我们可以减少此类问题的重复。 (2认同)