首页 文章

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

提问于
浏览
1

我想在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 的相关部分:

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 回答

  • 1

    我想你可能想做一些改变 .

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

    正如RT5754所指出的那样,强迫SKScene转换为SKSpriteNode并发生 let firstBody = contact.bodyA.node as! SKSpriteNode 崩溃 .

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

    • 为墙/边框添加物理类别 . 就像是:
    static let sceneBorder :UInt32 = 0x1 << 4
    
    • 更新边界和球节点以获得碰撞物理:
    ballNode.physicsBody?.collisionBitMask = physicsCategory.sceneBorder
    borderNode.physicsBody?.collisionBitMask = physicsCategory.ballOne + physicsCategory.ballTwo
    
    • 处理其他联系逻辑时, 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)
      }
    
  • 0

    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)
    }
    

相关问题