我无法让我的应用程序检测到碰撞

时间:2017-09-02 01:31:39

标签: ios swift xcode sprite-kit

class GameScene: SKScene, SKPhysicsContactDelegate {

    let balls = [
        SKSpriteNode(imageNamed: "blueball.png"),
        SKSpriteNode(imageNamed: "greenball.png"),
        SKSpriteNode(imageNamed: "realredball.png"),
        ]

    let redRectangle = SKSpriteNode(imageNamed: "redrectangle.png")
    let blueRectangle = SKSpriteNode(imageNamed: "bluerectangle.png")
    let greenRectangle = SKSpriteNode(imageNamed: "greenrectangle.png")

    let blueBallCategory: UInt32 = 0x1 << 0
    let greenBallCategory: UInt32 = 0x1 << 1
    let realRedBallCategory: UInt32 = 0x1 << 2
    let redRectangleCategory: UInt32 = 0x1 << 3
    let blueRectangleCategory: UInt32 = 0x1 << 4
    let greenRectangleCategory: UInt32 = 0x1 << 5

    override func didMove(to view: SKView) {
        spawnBallsandRectangles()
        physicsWorld.contactDelegate = self
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        physics()
    }

    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
        }

       if firstBody.categoryBitMask == blueBallCategory 
          && secondBody.categoryBitMask == redRectangleCategory {
             print("dead")
        }
    }

    func spawnBallsandRectangles() {
        let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
        ball.position = CGPoint(x: 0, y: 250)
        ball.size = CGSize(width: 70, height: 70)

        balls[0].physicsBody?.categoryBitMask = blueBallCategory
        balls[1].physicsBody?.categoryBitMask = greenBallCategory
        balls[2].physicsBody?.categoryBitMask = realRedBallCategory
        balls[0].physicsBody?.contactTestBitMask = redRectangleCategory

        redRectangle.position = CGPoint(x: 0, y: -600)
        redRectangle.size = CGSize(width: 200, height: 20)
        redRectangle.physicsBody?.categoryBitMask = redRectangleCategory

        blueRectangle.position = CGPoint(x: -200, y: -600)
        blueRectangle.size = CGSize(width: 200, height: 20)
        blueRectangle.physicsBody?.categoryBitMask = blueRectangleCategory

        greenRectangle.position = CGPoint(x: 200, y: -600)
        greenRectangle.size = CGSize(width: 200, height: 20)
        greenRectangle.physicsBody?.categoryBitMask = greenRectangleCategory

        self.addChild(ball)
        self.addChild(redRectangle)
        self.addChild(blueRectangle)
        self.addChild(greenRectangle)
    }

    func physics() {
        for ball in balls {
            ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height/2)
        }

        redRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
        redRectangle.physicsBody?.affectedByGravity = false
        redRectangle.physicsBody?.isDynamic = false

        blueRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
        blueRectangle.physicsBody?.affectedByGravity = false

        greenRectangle.physicsBody = SKPhysicsBody(rectangleOf: redRectangle.size)
        greenRectangle.physicsBody?.affectedByGravity = false

    }
}

我希望蓝色球(ball[0])能够点击redRectangle节点并触发碰撞检测。我对它进行了编程,这样当蓝色球落在红色矩形上时,如果检测到碰撞,控制台将print ("dead")。它没有做到这一点。

注意:蓝色,红色或绿色球从屏幕顶部落下并落在蓝色,红色或绿色矩形上。但到目前为止,我只为蓝色球和红色矩形设置了检测碰撞代码。我希望有人可以提供帮助,非常感谢。

1 个答案:

答案 0 :(得分:0)

问题是您要为方法SKPhysicsBody中的节点分配physics()。方法spawnBallsandRectangles()将值分配给这些实体的categoryBitMask属性。由于您在spawnBallsandRectangles()之前调用了physics(),因此这些实体尚不存在,并且位掩码的分配失败。

我会将所有设置代码从physics()移动到spawnBallsandRectangles(),以便您可以在尝试为其属性指定值之前设置物理主体。要让球保持静止直到触摸,您可以使用self.isPaused = true暂停场景,然后稍后使用self.isPaused = false重新开始,或者使用球上的isDynamic属性,这样它们就不会动态直到感动。

您可以使用此技术来检测触摸的球,然后在触摸后使其动态化:How do I detect if an SKSpriteNode has been touched

我使用最后一种技术重新编写代码来演示。

class GameScene: SKScene, SKPhysicsContactDelegate {
  let balls = [
    SKSpriteNode(imageNamed: "blueball.png"),
    SKSpriteNode(imageNamed: "greenball.png"),
    SKSpriteNode(imageNamed: "realredball.png"),
    ]

  let redRectangle = SKSpriteNode(imageNamed: "redrectangle.png")
  let blueRectangle = SKSpriteNode(imageNamed: "bluerectangle.png")
  let greenRectangle = SKSpriteNode(imageNamed: "greenrectangle.png")

  let blueBallCategory: UInt32 = 0x1 << 0
  let greenBallCategory: UInt32 = 0x1 << 1
  let realRedBallCategory: UInt32 = 0x1 << 2
  let redRectangleCategory: UInt32 = 0x1 << 3
  let blueRectangleCategory: UInt32 = 0x1 << 4
  let greenRectangleCategory: UInt32 = 0x1 << 5

  override func didMove(to view: SKView) {
    // set up all properties for balls and rectangles
    spawnBallsandRectangles()
    self.physicsWorld.contactDelegate = self
  }

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // find node touched
    guard let touched = touches.first else { return }
    let position = touched.location(in: self)
    let touchedNode = self.atPoint(position)

    // if it's a ball then start it falling
    if touchedNode.name == "ball" {
      touchedNode.physicsBody?.isDynamic = true
    }
  }

  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
    }

    if firstBody.categoryBitMask == blueBallCategory
      && secondBody.categoryBitMask == redRectangleCategory {
      print("dead")
    }
  }

  /// Convenience method to set up the rectangles
  static func setupRectangle(rectangle: SKSpriteNode,
                             category: UInt32,
                             position: CGPoint) {
    rectangle.position = position
    rectangle.size = CGSize(width: 200, height: 20)
    let physicsBody = SKPhysicsBody(rectangleOf: rectangle.size)
    physicsBody.affectedByGravity = false
    physicsBody.isDynamic = false
    physicsBody.categoryBitMask = category
    rectangle.physicsBody = physicsBody
  }

  func spawnBallsandRectangles() {
    for ball in balls {
      // name them to later identify them when touched
      ball.name = "ball"

      // give it a physics body and freeze it
      let physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height/2)
      physicsBody.isDynamic = false
      ball.physicsBody = physicsBody
    }

    let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
    ball.position = CGPoint(x: 0, y: 250)
    ball.size = CGSize(width: 70, height: 70)

    balls[0].physicsBody?.categoryBitMask = blueBallCategory
    balls[1].physicsBody?.categoryBitMask = greenBallCategory
    balls[2].physicsBody?.categoryBitMask = realRedBallCategory
    balls[0].physicsBody?.contactTestBitMask = redRectangleCategory

    GameScene.setupRectangle(rectangle: redRectangle,
                             category: redRectangleCategory,
                             position: CGPoint(x: 0, y: -600))
    GameScene.setupRectangle(rectangle: blueRectangle,
                             category: blueRectangleCategory,
                             position: CGPoint(x: -200, y: -600))
    GameScene.setupRectangle(rectangle: greenRectangle,
                             category: greenRectangleCategory,
                             position: CGPoint(x: 200, y: -600))

    self.addChild(ball)
    self.addChild(redRectangle)
    self.addChild(blueRectangle)
    self.addChild(greenRectangle)
  }
}