【问题标题】:How to Detect collision in Swift, Sprite kit如何在 Swift、Sprite 套件中检测碰撞
【发布时间】:2018-12-04 14:59:14
【问题描述】:

我一直在用 Swift 编写这个简单的太空游戏,直到遇到检测碰撞的问题。在浏览了论坛、教程等之后,我尝试通过像这样声明位掩码来实现冲突:

对象 1

    enemy?.physicsBody = SKPhysicsBody(circleOfRadius: ((enemy?.size.width)!/2))
    enemy?.physicsBody?.categoryBitMask = enemyBitMask
    enemy?.physicsBody?.contactTestBitMask = bulletBitMask
    enemy?.physicsBody?.collisionBitMask = 0

对象 2

    bullet?.physicsBody? = SKPhysicsBody(rectangleOf: (bullet?.size)!)
    bullet?.physicsBody?.categoryBitMask =  bulletBitMask
    bullet?.physicsBody?.contactTestBitMask =  enemyBitMask
    bullet?.physicsBody?.collisionBitMask = 0
    bullet?.physicsBody?.usesPreciseCollisionDetection = true

我还在

中放了一个打印语句
func didBegin(_ contact: SKPhysicsContact) { print("Hello") }

这是我如何配置我的精灵:

    func CreateNewEnemy() {
    var enemy : SKSpriteNode?

       let moveEnemyDown = SKAction.repeatForever(SKAction.moveBy(x: 0, y: -1, duration: 0.01))
       let rotateEnemy = SKAction.repeatForever(SKAction.rotate(byAngle: 25, duration: 5))

      let enemyXpos = randomNum(high:  self.frame.size.width/2, low: -1 * self.frame.size.width/2)
      let enemyYpos = randomNum(high:  2.5*self.frame.size.height, low: self.frame.size.height/2)
      let enemyOrigin : CGPoint = CGPoint(x: enemyXpos, y: enemyYpos)

      enemy = SKSpriteNode(imageNamed: possibleEnemyImage[Int(arc4random_uniform(4))])
      print(enemy?.size.height)
      enemy?.scale(to: CGSize(width: player.size.height, height: player.size.height))
      print(enemy?.size.height)
      enemy?.position = enemyOrigin
      enemy?.run(moveEnemyDown)
      enemy?.run(rotateEnemy)
      let enemyRadius : CGFloat = (enemy?.size.width)!/2
      print(enemyRadius)

      enemy?.physicsBody? = SKPhysicsBody(circleOfRadius: enemyRadius)

      enemy?.physicsBody?.categoryBitMask = enemyCategory
      enemy?.physicsBody?.contactTestBitMask = bulletCategory
      enemy?.physicsBody?.collisionBitMask = 0
      enemy?.zPosition = 1

      enemiesArray.append(enemy!)
      self.addChild(enemy!)
}

创建敌人(在确实移动到视图函数中调用)

    func CreateAllEnemies(amountOfEnemies : UInt8) {
    for _ in 0...amountOfEnemies {
        CreateNewEnemy()
    }
}

和另一个精灵

    func CreateNewBullet() {
     let bulletOrigin : CGPoint = CGPoint(x: player.position.x, y: player.position.y+player.size.height/2)
     let moveBulletUp = SKAction.repeatForever(SKAction.moveBy(x: 0, y: 3, duration: 0.01))

     var bullet : SKSpriteNode?
     bullet = SKSpriteNode(imageNamed: "bulletImage")
     bullet?.position = bulletOrigin
     bullet?.run(moveBulletUp)

     bullet?.physicsBody? = SKPhysicsBody(rectangleOf: (bullet?.size)!)
     bullet?.physicsBody?.categoryBitMask =  bulletCategory
     bullet?.physicsBody?.contactTestBitMask = enemyCategory
     bullet?.physicsBody?.collisionBitMask = 0
     bullet?.physicsBody?.isDynamic = true
     bullet?.physicsBody?.usesPreciseCollisionDetection = true
     bullet?.zPosition = 1

     bulletsArray.append(bullet!)
     self.addChild(bullet!)
}

这个是用计时器创建的

bulletTimer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(CreateNewBullet) , userInfo: nil, repeats: true)

不幸的是,在我看到两个对象接触后,它没有在控制台中打印任何内容。

【问题讨论】:

  • 将物理体代理设置为self。
  • @ElTomato 你的意思是物理世界

标签: ios swift sprite-kit skphysicsbody


【解决方案1】:
  1. 定义独特的类别,确保您的班级是SKPhysicsContactDelegate,并让自己成为物理联系人代表:

//Physics categories

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

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

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

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

  1. 设置碰撞:

enemy.physicsBody?.collisionBitMask = 0 // enemy collides with nothing bullet.physicsBody?.collisionBitMask = 0 // bullet collides with nothing

甚至:

for node in [enemy, bullet] {
   node.physicsBody?.collisionBitMask = 0 //  collides with nothing
   }
  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")
     }

}

【讨论】:

  • 我按照你说的做了,但它仍然不会打印任何东西
  • @ArjunBemarkar 那么你需要为你的问题提供更好的背景。
  • 听起来“didBegin”根本没有被调用。这段代码可以工作,但不是一个完整的程序,所以如果你把 sn-ps 的顺序弄错了,它仍然不能工作。您可以发布初始化精灵并将它们放置在场景中的代码吗?
  • 好的,我把创建精灵的方式和添加到场景中
  • 我不认为 'bullet' 有物理实体,因为您在 bullet?.physicsBody? = SKPhysicsBody... 中使用了可选链接,如果没有 physicBody,则没有碰撞或接触。试试bullet?.physicsBody = SKPhysicsBody(rectangleOf: (bullet?.size)!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-15
  • 1970-01-01
  • 2014-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多