2

I have a SKNode with userInteractionEnabled=true and touchesEnded overridden.

Since touchesEnded will be called at any time even when i move my finger out of the SKNode i want to be sure the touch ends within the SKNode, only then i want to count this as valid tap.

So i did the following:

class Tile : SKNode {
  var level:Int!
  init(tileWidth: CGFloat, level: Int) {
    super.init()
    self.name = "lvlseltile"
    self.level = Int(level)
    self.userInteractionEnabled = true
    let node = SKShapeNode(rect: CGRect(x: 0, y: 0, width: tileWidth, height: tileWidth))
    node.fillColor = UIColor.grayColor()
    self.addChild(node)
    let textNode = SKLabelNode(text: String(level))
    textNode.fontSize = 24
    textNode.fontColor = UIColor.whiteColor()
    textNode.horizontalAlignmentMode = .Center
    textNode.verticalAlignmentMode = .Center
    textNode.position = CGPoint(x: tileWidth/2, y: tileWidth/2)
    self.addChild(textNode)
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let location = touches.first?.locationInNode(self)
    if self.containsPoint(location!) {
        print("tapped tile")
    }
  }
}

Since im checking the location IN the current node, i get the relative coordinates from the current SKNodes coordinate system.

But self.containsPoint always returns FALSE. My SKNode is 40x40 big, my touch is at like 20x20, so in the center of the node, but it still returns FALSE.

Why that?

I know i can do a workaround like checking the touch location if x>0 && x<=40 and y>= and y<=40. But this is what i actually expect from self.containsPoint to do. What am i doing wrong?

NovumCoder
  • 4,349
  • 9
  • 43
  • 58

1 Answers1

1

An SKNode has width and height equal to 0

That's why the touch end location is always outside the SKNode.

The frame.size value of an SKNode is actually different greater than zero for subclasses that need to draw some content like SKSpriteNode or SKLabelNode.

From the official docs:

The frame property provides the bounding rectangle for a node’s visual content, modified by the scale and rotation properties. The frame is non-empty if the node’s class draws content. Each node subclass determines the size of this content differently. In some subclasses, the size of the node’s content is declared explicitly, such as in the SKSpriteNode class. In other subclasses, the content size is calculated implicitly by the class using other object properties. For example, an SKLabelNode object determines its content size using the label’s message text and font characteristics.

So why touchesEnded is called on an SKNode if its area is 0?

I don't know. I created a test SpriteKit project and I added my custom SKNode to the scene.

class MyNode: SKNode {

    override init() {
        super.init()
        userInteractionEnabled = true
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        userInteractionEnabled = true
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        print("touchesEnded!")
    }
}

However after many test I am unable to tap on it, (as expected since it has 0 area). I don't know how you manage to set the size of your SKNode to 40 x 40 and why your touchesEnded gets triggered. If you want you can show me more code.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148