I am having trouble with contains(_:)
to check if an SKSpriteNode
contains a point. Specifically a point from UIPanGestureRecognizer.location(in:)
.
Drawing two boxes (red and green) on the screen as SKSpriteNodes
, another node (colored yellow) is added and will be dragged across the scene using an UIPanGestureRecognizer
.
The result of contains(_:)
seems to depend on the parent of the node that is being dragged, which I don't expect. It should simply check if a specific CGPoint
lies inside of the coordinates of a node.
var box1: SKSpriteNode?
var box2: SKSpriteNode?
var draggingNode: SKSpriteNode?
box1 = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
box1?.position = CGPoint(x: 100, y: 100)
addChild(box1!)
box2 = SKSpriteNode(color: .green, size: CGSize(width: 50, height: 50))
box2?.position = CGPoint(x: 200, y: 200)
addChild(box2!)
draggingNode = SKSpriteNode(color: .yellow, size: CGSize(width: 25, height:25))
box1!.addChild(draggingNode!)
As seen above, the yellow draggingNode
is a child of the red node box1
.
Here is the gesture recogniser code that moves the draggingNode
and print outs the results of the test:
@objc func panned(sender: UIPanGestureRecognizer) {
let pointInView: CGPoint = sender.location(in: view)
let pointInScene = convertPoint(fromView: pointInView)
if sender.state == .changed {
let translation = sender.translation(in: view)
draggingNode?.position.x += translation.x
draggingNode?.position.y -= translation.y
sender.setTranslation(.zero, in: view)
print("is in box1: ", box1!.contains(pointInScene))
print("is in box2: ", box2!.contains(pointInScene))
}
box1!.contains(pointInScene)
only returns true
if the draggingNode
is actually above box1
.box1!.contains(pointInScene)
always returns true
, no matter if the draggingNode
is dragged above box1
or not.For box2
, of which the draggingNode
is not a child, the results are correct.
draggingNode
as a child of box2
, the results are reversed: box2!.contains(pointInScene)
now always returns true
and box1!.contains(pointInScene)
works correctly.draggingNode
as a child of the SKScene
itself, everything works as expected.Question: Why is the parent of draggingNode
influencing the result of contains(_:)
, and how to fix it?
the reason is that if you add a child node to a parent they effectively create a two node system. and this affects the frame size. if you look at box1?.calculateAccumulatedFrame()
you will see that box1's frame expands to include wherever the yellow draggingNode position is.
you are getting strange results because yellow is effectively doing a hit test against a rectangle that it's own position is helping to define.
solution: add both box1 and draggingNode to a third parent node (let's call it "container"). then box1's accumulated frame will not vary during the pan gesture, and your hit tests will be accurate.