1
votes

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?

1
Can I see how you are setting the size of your SKNode?Luca Angeletti
just updated my code block showing the complete subclass of SKNodeNovumCoder
strange, i just realized, self.frame of my class returns 0,0 in size. that must be the reason. i guess i have to define the frame rect in my class in order to make it with some size.NovumCoder
You cannot. The frame of SKNode is 0 x 0. Please read my answer.Luca Angeletti
I updated my code but I stil cannot receive touch on the SKNode and that's correct. What I don't understand is why you do receive touch events on your SKNode...Luca Angeletti

1 Answers

0
votes

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.