SpriteKit: почему containsPoint of SKNode возвращает false

У меня есть SKNode с переопределением userInteractionEnabled=true и touchesEnded.

Поскольку touchesEnded будет вызываться в любое время, даже когда я убираю палец с SKNode, я хочу быть уверенным, что касание заканчивается внутри SKNode, только тогда я хочу считать это действительным нажатием.

Поэтому я сделал следующее:

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")
    }
  }
}

Поскольку я проверяю местоположение В текущем узле, я получаю относительные координаты из текущей системы координат SKNodes.

Но self.containsPoint всегда возвращает FALSE. Мой SKNode имеет размер 40x40, мое касание примерно 20x20, то есть в центре узла, но все равно возвращает FALSE.

Почему так?

Я знаю, что могу найти обходной путь, например, проверить местоположение касания, если x> 0 && x‹=40 и y>= и y‹=40. Но это то, что я на самом деле ожидаю от self.containsPoint. Что я делаю не так?


person NovumCoder    schedule 02.08.2016    source источник
comment
Могу ли я посмотреть, как вы устанавливаете размер вашего SKNode?   -  person Luca Angeletti    schedule 03.08.2016
comment
только что обновил блок кода, показывающий полный подкласс SKNode   -  person NovumCoder    schedule 03.08.2016
comment
странно, я только что понял, что self.frame моего класса возвращает размер 0,0. это должно быть причиной. Я думаю, мне нужно определить прямоугольник кадра в моем классе, чтобы сделать его с некоторым размером.   -  person NovumCoder    schedule 03.08.2016
comment
Вы не можете. Кадр SKNode 0 x 0. Пожалуйста, прочитайте мой ответ.   -  person Luca Angeletti    schedule 03.08.2016
comment
Я обновил свой код, но по-прежнему не могу получить доступ к SKNode, и это правильно. Чего я не понимаю, так это почему вы получаете события касания на своем SKNode...   -  person Luca Angeletti    schedule 03.08.2016
comment
Пожалуйста, добавьте print('touchesEnded') в качестве первой строки вашего метода touchesEnded и дайте мне знать, если вы увидите это в журнале.   -  person Luca Angeletti    schedule 03.08.2016
comment
Да. я использую этот класс как плитку, которую можно осязать. я не знаю, почему это не должно работать, потому что SKNode имеет накопленный кадр. интересно, почему containsPoint не использует накопленный размер SKNode   -  person NovumCoder    schedule 03.08.2016
comment
Я не думаю, что накопленный кадр является автоматическим для SKNode.   -  person Luca Angeletti    schedule 03.08.2016


Ответы (1)


SKNode имеет ширину и высоту, равные 0

Вот почему место касания всегда находится за пределами SKNode.

Значение frame.size для SKNode на самом деле отличается от нуля для подклассов, которым необходимо отрисовывать некоторый контент, например SKSpriteNode или SKLabelNode.

Из официальной документации:

Свойство frame предоставляет ограничивающий прямоугольник для визуального содержимого узла, измененного свойствами масштаба и поворота. Фрейм непуст, если класс узла рисует содержимое. Каждый подкласс узла по-разному определяет размер этого содержимого. В некоторых подклассах размер содержимого узла объявляется явно, например, в классе SKSpriteNode. В других подклассах размер содержимого вычисляется классом неявно с использованием других свойств объекта. Например, объект SKLabelNode определяет размер своего содержимого, используя текст сообщения метки и характеристики шрифта.

Так почему же touchesEnded вызывается на SKNode, если его площадь равна 0?

Я не знаю. Я создал тестовый проект SpriteKit и добавил в сцену свой SKNode.

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!")
    }
}

Однако после многих тестов я не могу нажать на него (как и ожидалось, поскольку он имеет 0 области). Я не знаю, как вам удается установить размер вашего SKNode на 40 x 40 и почему срабатывает ваш touchesEnded. Если вы хотите, вы можете показать мне больше кода.

person Luca Angeletti    schedule 02.08.2016