问题
in SpriteKit we detect the in the didBeginContact method. but this looks a bit stupid to do something like that: func didBeginContact(contact: SKPhysicsContact) {
if let contactA = contact.bodyA.node?.name {
if let contactB = contact.bodyB.node?.name {
//now that we have safely unwrapped these nodes, we can operate on them
if contactA == "ball" {
collisionBetweenBall(contact.bodyA.node!, object: contact.bodyB.node!)
} else if contactB == "ball" {
collisionBetweenBall(contact.bodyB.node!, object: contact.bodyA.node!)
}
}
}
}
is there any way I can ensure that bodyA is always a ball? is there any rules related to categorybitmask?
回答1:
If you are using simple categories, with each physics body belonging to only one category, then this alternative form of didBeginContact may be more readable:
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case categoryBitMask.ball | categoryBitMask.something:
print("Collision between ball and something")
let ballNode = contact.bodyA.categoryBitMask == categoryBitMask.ball ? contact.bodyA.node! : contact.bodyB.node!
ballNode.pop()
score += 10
default :
//Some other contact has occurred
print("Some other contact")
}
}
Note that if your categories are more complicated, this won't work as the simple AND tests (categoryBitMask.ball | categoryBitMask.something
) won't match.
回答2:
Usually you would do this
First you would store your bit mask categories if you are not doing it already.
enum PhysicsCategory {
static let ball: UInt32 = 0x1 << 0
static let wall: UInt32 = 0x1 << 1
static let enemy: UInt32 = 0x1 << 2
}
and than assign them like so to your sprites
ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
ball.physicsBody?.contactTestBitMask = PhysicsCategory.wall | PhysicsCategory.enemy
wall.physicsBody?.categoryBitMask = PhysicsCategory.wall
wall.physicsBody?.contactTestBitMask = 0
enemy.physicsBody?.categoryBitMask = PhysicsCategory.enemy
enemy.physicsBody?.contactTestBitMask = 0
Note: Because ball checks for contacts with both wall and enemy in this example you would not need to tell wall or enemy to check contacts with ball. Its fine to do it on 1 physics body so you can set it to 0 on the others unless they have other specific contacts to look for.
Than you can check for them in the contact method like so without the double if statements.
func didBegin(_ contact: SKPhysicsContact) {
let firstBody: SKPhysicsBody
let secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
// Ball hit wall or wall hit ball
if (firstBody.categoryBitMask == PhysicsCategory.ball) && (secondBody.categoryBitMask == PhysicsCategory.wall) {
// Some code
}
// Ball hit enemy or enemy hit ball
if (firstBody.categoryBitMask == PhysicsCategory.ball) && (secondBody.categoryBitMask == PhysicsCategory.enemy) {
// Some code
}
}
Also do not forget to set the delegate in didMoveToView of your scene for this to work.
physicsWorld.contactDelegate = self
Hope this helps
来源:https://stackoverflow.com/questions/40436300/skphysicscontact-is-there-any-way-to-determine-which-body-is-a-and-b