如何防止触摸击中SKCropNode中的隐藏内容?

时间:2016-09-04 05:44:12

标签: objective-c swift sprite-kit skcropnode

我在我的游戏中大量使用SKCropNode用于风格用途,以及在我已经构建了我自己的SpriteKit版UIScrollView的情况下。我注意到,当我接触到触摸事件或手势识别器在某个点触发时,SKScene.nodeAtPoint(...)仍然会击中从裁剪节点隐藏在触点处的节点。

如何阻止SKScene.nodeAtPoint(...)点击裁剪的内容,而是返回其下方的下一个可见节点?

2 个答案:

答案 0 :(得分:3)

你做不到。一切都基于内容的框架,而作物节点,它是巨大的。您唯一能做的就是检查触摸点,使用nodesAtPoint获取所有节点,然后逐个枚举,通过检查像素数据或具有CGPath轮廓来检查触摸点是否触摸可见像素你的精灵,并检查你是否在里面。

答案 1 :(得分:1)

我设法绕着这个工作,但它并不漂亮,并且在每种情况下都不起作用。

这个想法是,当记录触摸时,我在那个点迭代所有节点。如果这些节点中的任何节点是(或者是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
    }
}