【问题标题】:How do I prevent touches from hitting hidden content in SKCropNode?如何防止触摸击中 SKCropNode 中的隐藏内容?
【发布时间】:2016-09-04 05:44:11
【问题描述】:

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

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

【问题讨论】:

    标签: objective-c swift sprite-kit skcropnode


    【解决方案1】:

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

    【讨论】:

    • 见这里:stackoverflow.com/questions/31950525/… 我会标记重复,但答案未被接受或反对。
    • 再次感谢骑士。裁剪节点似乎非常有限(甚至有些错误)。令人沮丧的一个重要原因。
    • 这不是问题,只是你没有正确使用它
    • 同意这种情况不是错误(但仍然是一个非常烦人的限制)。但是this 似乎有问题。
    • @BrentTraut SpriteKit 受到(我的猜测)预算、团队和灵感的限制。对于 SKWarpNode 和 SKCropNode,我认为他们甚至没有意识到他们即将实现的目标,他们也不了解设计师和创意人员如何构思和感知这些潜在能力。工程师们在历史上不是第一次忽视创造力……而且每个版本都存在错误,它们的明显性和缺乏透明度,它们何时会被修复,或者它们是否被认可。错误和限制,以及糟糕的文档。一个悲惨的案例。
    【解决方案2】:

    我设法解决了这个问题,但它并不漂亮,而且它并不适用于所有场景。

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

    【讨论】:

    • 测试节点的堆叠不需要发生,我很确定给出的列表是从上到下的 zorder。此外,当您击中面具的透明部分时,您仍在记录触摸,没有它就不会触发。我有一个问题,你的裁剪节点内的内容会改变吗?
    • 我在顶部提到我在点击透明部分时记录了触摸。如果没有一些非常讨厌的代码,我不知道如何解决这个问题。裁剪节点内的内容确实发生了变化,是的。
    • 裁剪节点以外的情况
    • 当裁剪节点在场景中时
    • 我使用裁剪节点的一部分是用于滚动容器。我在屏幕上同时有多个这样的,所以我猜里面和外面的内容都可以改变。
    猜你喜欢
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-09
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    相关资源
    最近更新 更多