SKSpriteNode 在 isUserInteractionEnabled false 时不让触摸通过
SKSpriteNode does not let touches pass through when isUserInteractionEnabled false
我正在尝试使用 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
并手动将触摸事件委托给适当的节点,但这会导致很多奇怪的行为。
如有任何帮助,我们将不胜感激。谢谢!
阅读您找到的实际来源:
/**
Controls whether or not the node receives touch events
*/
open var isUserInteractionEnabled: Bool
但这是指触摸的内部节点方法。
默认情况下 isUserInteractionEnabled
是 false 那么像你的覆盖层 SKSpriteNode
这样的子对象的触摸默认情况下是对主(或父)处理的简单触摸 class(对象在这里,存在,但如果你不执行任何操作,你只需触摸它)
要通过触摸浏览叠加层,您可以在 GameScene
中实现类似下面的代码。还请记住不要将 -1 用作 zPosition
,因为这意味着它在您的场景下方。
P.S. :我在你的精灵中添加了一个 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。禁用场景触摸,您应该会看到结果。
现在是这样说的:
The Hit-Testing Order Is the Reverse of Drawing Order In a scene, when
SpriteKit processes touch or mouse events, it walks the scene to find
the closest node that wants to accept the event. If that node doesn’t
want the event, SpriteKit checks the next closest node, and so on. The
order in which hit-testing is processed is essentially the reverse of
drawing order.
For a node to be considered during hit-testing, its
userInteractionEnabled property must be set to YES. The default value
is NO for any node except a scene node. A node that wants to receive
events needs to implement the appropriate responder methods from its
parent class (UIResponder on iOS and NSResponder on OS X). This is one
of the few places where you must implement platform-specific code in
SpriteKit.
但这可能并非总是如此,因此您需要检查 8 、 9 和 10 之间的一致性
我正在尝试使用 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
并手动将触摸事件委托给适当的节点,但这会导致很多奇怪的行为。
如有任何帮助,我们将不胜感激。谢谢!
阅读您找到的实际来源:
/**
Controls whether or not the node receives touch events
*/
open var isUserInteractionEnabled: Bool
但这是指触摸的内部节点方法。
默认情况下 isUserInteractionEnabled
是 false 那么像你的覆盖层 SKSpriteNode
这样的子对象的触摸默认情况下是对主(或父)处理的简单触摸 class(对象在这里,存在,但如果你不执行任何操作,你只需触摸它)
要通过触摸浏览叠加层,您可以在 GameScene
中实现类似下面的代码。还请记住不要将 -1 用作 zPosition
,因为这意味着它在您的场景下方。
P.S. :我在你的精灵中添加了一个 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。禁用场景触摸,您应该会看到结果。
现在是这样说的:
The Hit-Testing Order Is the Reverse of Drawing Order In a scene, when SpriteKit processes touch or mouse events, it walks the scene to find the closest node that wants to accept the event. If that node doesn’t want the event, SpriteKit checks the next closest node, and so on. The order in which hit-testing is processed is essentially the reverse of drawing order.
For a node to be considered during hit-testing, its userInteractionEnabled property must be set to YES. The default value is NO for any node except a scene node. A node that wants to receive events needs to implement the appropriate responder methods from its parent class (UIResponder on iOS and NSResponder on OS X). This is one of the few places where you must implement platform-specific code in SpriteKit.
但这可能并非总是如此,因此您需要检查 8 、 9 和 10 之间的一致性