当isUserInteractionEnabled为false时,SKSpriteNode不允许触摸通过

时间:2016-11-04 06:07:27

标签: ios swift sprite-kit touch

我尝试使用SKSpriteNode在SpriteKit中创建叠加层。但是,我希望触摸通过叠加层,因此我将isUserInteractionEnabled设置为false。但是,当我这样做时,SKSpriteNode仍然似乎吸收了所有的触摸,并且不允许底层节点做任何事情。

以下是我所谈论的一个例子:

class 

TouchableSprite: SKShapeNode {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("Touch began")
    }
}

class GameScene: SKScene {
    override func sceneDidLoad() {
        // Creat touchable
        let touchable = TouchableSprite(circleOfRadius: 100)
        touchable.zPosition = -1
        touchable.fillColor = SKColor.red
        touchable.isUserInteractionEnabled = true
        addChild(touchable)


        // Create overlay
        let overlayNode = SKSpriteNode(imageNamed: "Fade")
        overlayNode.zPosition = 1
        overlayNode.isUserInteractionEnabled = false
        addChild(overlayNode)
    }
}

我尝试了将SKSpriteNode子类化并手动将触摸事件委托给相应的节点,但这会导致许多奇怪的行为。

非常感谢任何帮助。谢谢!

2 个答案:

答案 0 :(得分:6)

阅读您找到的实际来源:

/**
  Controls whether or not the node receives touch events
*/
open var isUserInteractionEnabled: Bool

但这指的是内部节点触摸方法。 默认情况下,isUserInteractionEnabled false ,默认情况下,对您的重叠SKSpriteNode的触摸是对主(或父)类(对象)的简单触摸在这里,存在,但如果你没有实施任何行动,你只需触摸它)

要通过触摸浏览您的叠加层,您可以在GameScene上实现下面的代码。请记住,不要将-1用作zPosition,因为它意味着它位于您的场景之下。

PS :我已向您的精灵添加name以将其召回touchesBegan,但您可以为GameScene创建全局变量:

override func sceneDidLoad() {
        // Creat touchable
        let touchable = TouchableSprite(circleOfRadius: 100)
        touchable.zPosition = 0
        touchable.fillColor = SKColor.red
        touchable.isUserInteractionEnabled = true
        touchable.name = "touchable"
        addChild(touchable)
        // Create overlay
        let overlayNode = SKSpriteNode(imageNamed: "fade")
        overlayNode.zPosition = 1
        overlayNode.name = "overlayNode"
        overlayNode.isUserInteractionEnabled = false
        addChild(overlayNode)
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("GameScene Touch began")
        for t in touches {
            let touchLocation = t.location(in: self)
            if let overlay = self.childNode(withName: "//overlayNode") as? SKSpriteNode {
                if overlay.contains(touchLocation) {
                    print("overlay touched")
                    if let touchable = self.childNode(withName: "//touchable") as? TouchableSprite {
                        if touchable.contains(touchLocation) {
                            touchable.touchesBegan(touches, with: event)
                        }
                    }
                }
            }
        }
    }
}

答案 1 :(得分:3)

你需要小心zPosition。有可能走到幕后,让事情变得复杂。

更糟糕的是触摸事件的顺序。我记得读过它是基于节点树而不是zPosition。禁用场景触摸,您应该看到结果。

这就是它现在所说的:

  

命中测试顺序是绘制顺序的反转在场景中,何时   SpriteKit处理触摸或鼠标事件,它遍历场景进行查找   想要接受事件的最近节点。如果该节点没有   想要事件,SpriteKit会检查下一个最近的节点,依此类推。该   处理命中测试的顺序基本上是相反的   绘图顺序。

     

对于在命中测试期间要考虑的节点,它   userInteractionEnabled属性必须设置为YES。默认值   除场景节点外的任何节点都为NO。想要接收的节点   事件需要从它实现适当的响应方法   父类(iOS上的UIResponder和OS X上的NSResponder)。这是一   您必须在其中实现特定于平台的代码的几个地方   SpriteKit。

但情况并非总是如此,因此您需要检查8,9和10之间的一致性