Swift SpriteKit碰撞检测异常:所有物体均触发碰撞回调
Looks like you're hitting a classic SpriteKit physics mask misconfiguration issue—let's break this down and get it sorted. The core problem here is almost certainly that either your physics masks aren't properly isolated between the two object types, or you're not validating the right masks in your contact delegate callback.
Step 1: Use an Enum to Manage Physics Categories (Avoid Hard-Coding!)
First, let's define clear, unique categories for all your entities. This eliminates the risk of overlapping mask values that cause false positives:
enum PhysicsCategory: UInt32 { case leftCar = 1 << 0 case rightCar = 1 << 1 case collisionObject = 1 << 2 case rotatingObject = 1 << 3 // Add a ground category if you need it later }
Each category uses a unique bit shift, so no two categories will ever overlap.
Step 2: Configure Physics Bodies Correctly
Now set up the masks for each node type—this is where most people slip up. Remember, SpriteKit uses three key masks for contacts/collisions:
categoryBitMask: What type of object this iscontactTestBitMask: Which object types should trigger a contact callbackcollisionBitMask: Which object types this should physically collide with (push apart)
For Your Left/Right Cars:
Since you only want rotating objects to trigger interactions, set their contactTestBitMask to only detect rotating objects. We'll disable physical collisions (set to 0) since the cars are stationary:
// Left Car Setup leftCar.physicsBody?.categoryBitMask = PhysicsCategory.leftCar.rawValue leftCar.physicsBody?.collisionBitMask = 0 // No physical collisions needed leftCar.physicsBody?.contactTestBitMask = PhysicsCategory.rotatingObject.rawValue leftCar.physicsBody?.isDynamic = false // Keep car fixed in place // Right Car Setup (mirror of left) rightCar.physicsBody?.categoryBitMask = PhysicsCategory.rightCar.rawValue rightCar.physicsBody?.collisionBitMask = 0 rightCar.physicsBody?.contactTestBitMask = PhysicsCategory.rotatingObject.rawValue rightCar.physicsBody?.isDynamic = false
For Collision-Type Objects:
These should never trigger contact callbacks with cars, so set their contactTestBitMask to 0. You can set collisionBitMask to whatever you need (like ground) but leave out car categories:
collisionObject.physicsBody?.categoryBitMask = PhysicsCategory.collisionObject.rawValue collisionObject.physicsBody?.contactTestBitMask = 0 // No contact callbacks collisionObject.physicsBody?.collisionBitMask = 0 // Or add ground category if needed
For Rotating-Type Objects:
These need to trigger callbacks with both cars, so include both car categories in their contactTestBitMask:
rotatingObject.physicsBody?.categoryBitMask = PhysicsCategory.rotatingObject.rawValue rotatingObject.physicsBody?.contactTestBitMask = PhysicsCategory.leftCar.rawValue | PhysicsCategory.rightCar.rawValue rotatingObject.physicsBody?.collisionBitMask = 0 // Or add ground category if needed
Step 3: Fix Your Contact Delegate Callback
Even with correct masks, if your didBegin(_:) function doesn't verify both colliding objects, you'll still get false positives. Make sure you explicitly check that one object is a car and the other is a rotating object:
func didBegin(_ contact: SKPhysicsContact) { let bodyA = contact.bodyA let bodyB = contact.bodyB // Check if we have a left car + rotating object pair let isLeftCarHit = (bodyA.categoryBitMask == PhysicsCategory.leftCar.rawValue && bodyB.categoryBitMask == PhysicsCategory.rotatingObject.rawValue) || (bodyB.categoryBitMask == PhysicsCategory.leftCar.rawValue && bodyA.categoryBitMask == PhysicsCategory.rotatingObject.rawValue) // Check if we have a right car + rotating object pair let isRightCarHit = (bodyA.categoryBitMask == PhysicsCategory.rightCar.rawValue && bodyB.categoryBitMask == PhysicsCategory.rotatingObject.rawValue) || (bodyB.categoryBitMask == PhysicsCategory.rightCar.rawValue && bodyA.categoryBitMask == PhysicsCategory.rotatingObject.rawValue) if isLeftCarHit { print("Hit left car!") // Add your left car rotation logic here leftCar.run(SKAction.rotate(byAngle: .pi, duration: 0.5)) } else if isRightCarHit { print("Hit right car!") // Add your right car rotation logic here rightCar.run(SKAction.rotate(byAngle: .pi, duration: 0.5)) } // All other collisions (like collision objects hitting cars) are ignored }
Quick Checks to Rule Out Other Issues
- Ensure your scene's
physicsWorld.contactDelegateis set toself(add this indidMove(to view: SKView):physicsWorld.contactDelegate = self) - Double-check that none of your nodes have a
nilphysics body (if you forgot to initializephysicsBody, masks won't work) - Don't mix up
collisionBitMaskandcontactTestBitMask—they control two entirely different behaviors!
内容的提问来源于stack exchange,提问作者GOK1970

