简体   繁体   English

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

[英]How do I prevent touches from hitting hidden content in SKCropNode?

I'm making pretty heavy use of SKCropNode in my game both for stylistic uses and also in one case where I've built my own SpriteKit version of UIScrollView . 我在游戏中大量使用了SKCropNode ,以用于样式用途,并且在一种情况下,我已经构建了自己的SpriteKit版本的UIScrollView I've noticed that when I get a touch event or when a gesture recognizer fires at a certain point, SKScene.nodeAtPoint(...) is still hitting nodes that are hidden at the touch point from the crop node. 我注意到,当我发生触摸事件或手势识别器在某个点触发时, SKScene.nodeAtPoint(...)仍会击中在裁剪节点上触摸点处隐藏的节点。

How do I prevent SKScene.nodeAtPoint(...) from hitting cropped content, and instead return the next visible node beneath it? 如何防止SKScene.nodeAtPoint(...)击中裁剪的内容,而是返回其下面的下一个可见节点?

You can't. 你不能 Everything is based on the frame of the content, and with crop nodes, it is huge. 一切都基于内容的框架,并且具有裁剪节点,因此非常庞大。 The only thing you can do is check the point of touch, use nodesAtPoint to get all nodes, then enumerate one by one, checking whether or not the touch point is touching a visible pixel by either checking the pixel data, or having a CGPath outlining of your sprite and checking if you are inside that. 唯一可以做的就是检查触摸点,使用nodesAtPoint获取所有节点,然后一一枚举,通过检查像素数据或进行CGPath概述来检查触摸点是否在触摸可见像素。精灵,并检查您是否在其中。

I managed to work my way around this one, but it isn't pretty and it doesn't work in every scenario. 我设法解决了这个问题,但是它并不漂亮,并且并非在每种情况下都有效。

The idea is, when a touch is recorded, I iterate over all nodes at that point. 这个想法是,当记录触摸时,我将在该点上遍历所有节点。 If any of those nodes are (or are children of) SKCropNodes, I check the frame of the mask on the crop node. 如果这些节点中的任何一个是SKCropNodes(或是SKCropNodes的子代),则检查裁剪节点上的蒙版框架。 If the touch lies outside the mask, we know the node is not visible at that point and we can assume the touch didn't hit it. 如果触摸位于蒙版外部,则我们知道该点在该点不可见,并且可以假定触摸没有击中它。

The issue with this method is that I don't do any evaluation of transparency within the crop mask - I just assume it's a rectangle. 这种方法的问题在于,我没有对裁剪蒙版中的透明度做任何评估-我只是假设它是一个矩形。 If the mask is an abnormal shape, I may give false positives on node touches. 如果遮罩形状不正常,我可能会在节点触摸时给出误报。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM