Как предотвратить попадание касаний в скрытый контент в SKCropNode?

Я довольно сильно использую SKCropNode в моей игре как для стилистического использования, так и в одном случае, когда я построил свою собственную версию SpriteKit UIScrollView, Я заметил, что когда я получаю событие касания или когда распознаватель жестов срабатывает в определенный момент, SKScene.nodeAtPoint(...) все еще поражает узлы, которые скрыты в точке касания от узла обрезки.

Как я могу предотвратить SKScene.nodeAtPoint(...) от попадания обрезанного контента и возврата следующего видимого узла под ним?

2 ответа

Ты не можешь Все основано на фрейме контента, а с обрезанными узлами оно огромно. Единственное, что вы можете сделать, это проверить точку касания, использовать nodeAtPoint, чтобы получить все узлы, а затем перечислить один за другим, проверяя, касается ли точка касания видимого пикселя, либо проверяя данные пикселя, либо имея выделение CGPath вашего спрайта и проверки, если вы внутри этого.

Мне удалось обойти это, но это не красиво и не работает в каждом сценарии.

Идея заключается в том, что при касании я перебираю все узлы в этой точке. Если какой-либо из этих узлов является (или является потомком) узлом SKCropNodes, я проверяю рамку маски на узле обрезки. Если касание находится вне маски, мы знаем, что узел не видим в этой точке, и мы можем предположить, что касание не поразило его.

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

extension SKScene {
    // Get the node at a given point, but ignore those that are hidden due to SKCropNodes.
    func getVisibleNodeAtPoint(point: CGPoint) -> SKNode? {
        var testedNodes = Set<SKNode>()

        // Iterate over all the nodes hit by this click.
        for touchedNode in self.nodesAtPoint(point) {
            // If we've already checked this node, skip it. This happens because nodesAtPoint
            // returns both leaf and ancestor nodes, and we test the ancestor nodes while
            // testing leaf nodes.
            if testedNodes.contains(touchedNode) {
                continue
            }

            var stillVisible = true

            // Walk the ancestry chain of the target node starting with the touched
            // node itself.
            var currentNode: SKNode = touchedNode
            while true {
                testedNodes.insert(currentNode)

                if let currentCropNode = currentNode as? SKCropNode {
                    if let currentCropNodeMask = currentCropNode.maskNode {
                        let pointNormalizedToCurrentNode = self.convertPoint(point, toNode: currentCropNode)
                        let currentCropNodeMaskFrame = currentCropNodeMask.frame

                        // Check if the touch is inside the crop node's mask. If not, we
                        // know we've touched a hidden point.
                        if
                            pointNormalizedToCurrentNode.x < 0 || pointNormalizedToCurrentNode.x > currentCropNodeMaskFrame.size.width ||
                                pointNormalizedToCurrentNode.y < 0 || pointNormalizedToCurrentNode.y > currentCropNodeMaskFrame.size.height
                        {
                            stillVisible = false
                            break
                        }
                    }
                }

                // Move to next parent.
                if let parent = currentNode.parent {
                    currentNode = parent
                } else {
                    break
                }
            }

            if !stillVisible {
                continue
            }

            // We made it through the ancestry nodes. This node must be visible.
            return touchedNode
        }

        // No visible nodes found at this point.
        return nil
    }
}
Другие вопросы по тегам