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



我试图在SpriteKit中创建一个覆盖,通过使用SKSpriteNode。然而,我希望触摸通过覆盖,所以我设置isUserInteractionEnabled为假。然而,当我这样做时,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并手动将触摸事件委托给适当的节点,但这会导致很多奇怪的行为。

任何帮助都将非常感激。谢谢!

阅读您找到的实际来源:

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

但这指的是触摸的内部节点方法。默认情况下,isUserInteractionEnabledfalse,那么像你的覆盖SKSpriteNode这样的子类上的触摸是,默认情况下,一个简单的触摸处理到主(或父)类(对象在这里,存在,但如果你不实现任何动作,你只是触摸它)

通过触摸的叠加,你可以实现一个像下面这样的代码到你的GameScene。记住也不要使用-1作为zPosition,因为这意味着它在你的场景下面。

注::我已经在你的精灵中添加了一个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)
                        }
                    }
                }
            }
        }
    }
}

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

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

现在是这样写的:

在一个场景中,Hit-Testing Order与Drawing Order相反SpriteKit处理触摸或鼠标事件,它行走在场景中寻找想要接受事件的最近的节点。如果那个节点没有想要事件,SpriteKit检查下一个最近的节点,依此类推。的hit-testing的处理顺序基本上与画秩序。

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

但这可能并不总是这样,所以您需要检查8、9和10之间的一致性

最新更新