如何在SpriteKit中检测不同类型的碰撞

时间:2017-04-15 15:52:35

标签: ios swift swift3 sprite-kit collision-detection

我想在SpriteKit中检测两种不同类型的碰撞:

当ballOne击中goalOne并且当ballTwo击中goalTwo时:

到目前为止,我已添加了不同的物理类别:

struct physicsCategory {
    static let ballOne :UInt32 = 0x1 << 0
    static let goalOne :UInt32 = 0x1 << 1
    static let ballTwo :UInt32 = 0x1 << 2
    static let goalTwo :UInt32 = 0x1 << 3
}

以下是我班级的相关部分:

class gameScene: SKScene, SKPhysicsContactDelegate {

    var borderBody:SKPhysicsBody!

    var myscore:Int = 0
    var opponentScore:Int = 10

    override func sceneDidLoad() {

        super.sceneDidLoad()
        physicsWorld.contactDelegate = self

    }

    func didBegin(_ contact: SKPhysicsContact) {

        let firstBody = contact.bodyA.node as! SKSpriteNode
        let secondBody = contact.bodyB.node as! SKSpriteNode

        if ((firstBody.name == "ballOne") && (secondBody.name == "goalOne")) {
            collisionGoalOne(BallOne: firstBody, GoalOne: secondBody)
        }

        else {

        }
    }

    func collisionGoalOne(BallOne: SKSpriteNode, GoalOne: SKSpriteNode) {
        addScore()
    }

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

        let touch = touches.first
        let touchLocation = touch!.location(in: self)

        let ballOne = childNode(withName: "ballOne") as! SKSpriteNode
        ballOne.physicsBody?.categoryBitMask = physicsCategory.ballOne
        ballOne.physicsBody?.collisionBitMask = physicsCategory.goalOne
        ballOne.physicsBody?.contactTestBitMask = physicsCategory.goalOne
        ballOne.physicsBody?.isDynamic = true

        let goalOne = childNode(withName: "goalOne") as! SKSpriteNode
        goalOne.physicsBody?.categoryBitMask = physicsCategory.goalOne
        goalOne.physicsBody?.collisionBitMask = physicsCategory.ballOne
        goalOne.physicsBody?.contactTestBitMask = physicsCategory.ballOne
        goalOne.physicsBody?.isDynamic = false        
    }

}

现在,当球与墙壁碰撞时,应用程序崩溃

let firstBody = contact.bodyA.node as! SKSpriteNode

“无法将类型'appName.gameScene'(0x105320)的值转换为'SKSpriteNode'(0x1877b5c)。”

很想明白为什么会发生这种崩溃,以及这是否是一种很好的碰撞处理方法。谢谢。

2 个答案:

答案 0 :(得分:1)

FirstBody可能无法转换为SKSpriteNode,因此只有在检查了哪些节点发生碰撞后才创建该变量。

请注意,ballOne可以是bodyA或bodyB,因此请更改代码以检查两种可能性。

我改变了你的代码。希望这有帮助

if ((contact.bodyA.node?.name == "ballOne") && (contact.bodyB.node?.name == "goalOne")) {  
     let firstBody = contact.bodyA.node as! SKSpriteNode
     let secondBody = contact.bodyB.node as! SKSpriteNode
     collisionGoalOne(BallOne: firstBody, GoalOne: secondBody)
 } else if ((contact.bodyA.node?.name == "goalOne") && (contact.bodyB.node?.name == "ballOne")) {
     let firstBody = contact.bodyA.node as! SKSpriteNode
     let secondBody = contact.bodyB.node as! SKSpriteNode
     collisionGoalOne(BallOne: secondBody, GoalOne: firstBody)
}

答案 1 :(得分:1)

我认为您可能想要进行一些更改。

当您的球节点与墙壁接触时,我相信您的didBegin(_ contact: SKPhysicsContact)方法会被调用,其中一个物体作为球(SKNode)而另一个物体作为场景边界(SKScene) 。

强迫SKScene投射到SKSpriteNode,let firstBody = contact.bodyA.node as! SKSpriteNode崩溃,RT5754指出。

要解决此问题,您可以考虑以下事项:

  1. 为墙/边框添加物理类别。类似的东西:

     static let sceneBorder :UInt32 = 0x1 << 4
    
  2. 更新边框和球节点以进行碰撞物理:

    ballNode.physicsBody?.collisionBitMask = physicsCategory.sceneBorder
    borderNode.physicsBody?.collisionBitMask = physicsCategory.ballOne + physicsCategory.ballTwo
    
  3. 处理其他联系逻辑时,我的模式为 didBegin(_ contact: SKPhysicsContact) 是这样的:

    func didBegin(_ contact: SKPhysicsContact) {
      var firstBody: SKPhysicsBody = contact.bodyA
      var secondBody: SKPhysicsBody = contact.bodyB
    
      //in did begin contact, order the bodies by physics category
      if firstBody.categoryBitMask > secondBody.categoryBitMask {
        let temp = secondBody
        secondBody = firstBody
        firstBody = temp
      }
    
      //logic to handle contact is based on physicsCategory
      if secondBody.categoryBitMask == physicsCategory.whatever {
        methodToHandleWhatever(thingOne: firstBody, thingTwo: secondBody)
      }