Séraphin Hochart
Séraphin Hochart

Reputation: 193

SpriteKit : enumerateBodiesAtPoint not showing correct bodies

I have a few non-completed-circles rotating constantly and a user going from circle to circle. I removed all gravity, forces etc from my scene

Image A Image A

Image B Image B

Problem : I am trying to do a hit detection where I just check where the user is, and if there are SKNode's bodies at this point in the physics world of my scene. If it's a hit with the shape, the user can continue (image A), but fails if he is outside (image B)

Although the shapes are pretty complex, the scene.showPhysics seem to match my shapes precisely. (see image A and B)

let updatedOrigin = user.calculateAccumulatedFrame().origin
        user.scene?.physicsWorld.enumerateBodiesAtPoint(updatedOrigin, usingBlock: { (body, stop) in
            print("🍄 Shape contains \(body.node!.name)")
})

which prints

🍄 Shape contains Optional("User")
🍄 Shape contains Optional("circle")
🍄 Shape contains Optional("circle")
🍄 Shape contains Optional("circle")
🍄 Shape contains Optional("circle")
🍄 Shape contains Optional("Scene")

It prints the user and scene correctly, but also prints all the circle's shapes around, when there should only be one at this point, or none. The nodes are there, but the bodies physics should not hit.

Any ideas why it shows a hit for all those circles when it should only match 1 or none? Thanks!

Edit : additional info - I had similar results when using user.physicsBody?.allContactedBodies() - I am using a CGPath to create the PhysicsBody of my rotating node

Upvotes: 2

Views: 115

Answers (1)

0x141E
0x141E

Reputation: 12753

I created a simple test project with a scene containing 3 arcs with physics bodies and 3 rectangle shape-nodes that identify the bounding box for each arc. I then added a touch handler that places a small circle at the tap point and a label that identifies the nodes returned by enumerateBodiesAtPoint with the touch location as the parameter. The figure below shows the results of tapping at various locations in the scene.

enter image description here

From the test results, it's not obvious how enumerateBodiesAtPoint determines if a physics body contains the specified point or not. It is clear, though, that the method is not consistent with its documentation. I suggest that you avoid using it in your app.

Alternatively, you can use SpriteKit's built-in contact detection:

class GameScene: SKScene, SKPhysicsContactDelegate { 
    override func didMoveToView(view: SKView) {
        self.physicsWorld.contactDelegate = self
    }

    func didBeginContact(contact: SKPhysicsContact) {
        // Handle contacts between physics bodies here
    }
}

You can also test if a point is within a CGPath using CGPathContainsPoint. Here, you will need to iterate over the paths you used to create the arc-shaped physics bodies. The below figure shows the result of my test project that uses CGPathContainsPoint instead of enumerateBodiesAtPoint. You may need to convert the test point, with convertPoint, to the appropriate coordinate space prior passing it to CGPathContainsPoint.

enter image description here

Upvotes: 2

Related Questions