SpriteKit:如何检测从节点外部开始的节点上的触摸

时间:2023-01-16 23:08:26

SKNode A is a parent of SKNode B.

SKNode A是SKNode B的父母。

If touches begin inside of SKNode B, the touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) function gets called.

如果触摸在SKNode B内部开始,则会调用touchesMoved(_ touches:Set ,with event:UIEvent?)函数。

If, however, the touches begin outside of SKNode B but move into SKNode B, the touchesMoved function never gets called.

但是,如果触摸在SKNode B之外开始但移入SKNode B,则touchesMoved函数永远不会被调用。

One option is to handle all touch events inside SKNode A.

一种选择是处理SKNode A内的所有触摸事件。

However, there are many nodes contained inside SKNode A. Ideally, we could push touch functionality into each child, as opposed to handling everything from SKNode A.

但是,SKNode A中包含许多节点。理想情况下,我们可以将触摸功能推送到每个子节点,而不是处理SKNode A中的所有节点。

Is it possible to capture touch events that occur inside SKNode B even if they began outside of SKNode B?

是否有可能捕获SKNode B内部发生的触摸事件,即使它们是在SKNode B之外开始的?

1 个解决方案

#1


2  

When you hit your touchesBegan method, your touch is limited to the coordinate system of that node until the point it is ended. Moving onto another node will not change the coordinate system to the new node. If B is the only node that requires the touch, then you can add a child to cover the entire scene to ensure that B gets fired.

当您点击touchesBegan方法时,您的触摸仅限于该节点的坐标系,直到它结束。移动到另一个节点不会将坐标系更改为新节点。如果B是唯一需要触摸的节点,那么您可以添加一个子节点来覆盖整个场景,以确保B被触发。

class TouchNode : SKSpriteNode
{
    //if you need to override other inits do it here
    convenience init(withSize size:CGSize)
    {
       self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
       isUserInteractionEnabled = true

    }

    override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesBegan(touches:touches, withEvent:event)
    } 

    override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesMoved(touches:touches, withEvent:event)
    } 

    override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesEnded(touches:touches, withEvent:event)
    } 

    override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesCancelled(touches:touches, withEvent:event)
    } 

}

Then in your NodeB class:

然后在你的NodeB类中:

required init(coder aDecoder:NSCoder)
{
    super.init(coder:aDecoder)
    DispatchQueue.main.async{
        self.addChild(TouchNode(withSize:self.scene!.size))
    }
}
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

Edit: Misread question, but leaving the answer in case somebody else needs to go from inside the node to outside.

编辑:误读问题,但留下答案以防其他人需要从节点内部转到外部。

Think about it, you want to touch nodeB outside of nodeB, this does not make sense. It is like me poking the air and you crying that I am poking you. But if you absolutely need to go outside of the bounds, then add a child node to the sprite when you touch it that extends beyond the node itself, and be sure to transfer the touch back up to the parent

想想看,你想在nodeB之外触摸nodeB,这没有意义。就像我在戳风,你哭着说我在戳你。但是如果你绝对需要超出边界,那么当你触摸它超出节点本身时,将一个子节点添加到精灵中,并确保将触摸传递回父节点

class TouchNode : SKSpriteNode
{
    //if you need to override other inits do it here
    convenience init(withSize size:CGSize)
    {
       self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
       isUserInteractionEnabled = true

    }

    override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesBegan(touches:touches, withEvent:event)
    } 

    override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesMoved(touches:touches, withEvent:event)
    } 

    override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesEnded(touches:touches, withEvent:event)
    } 

    override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesCancelled(touches:touches, withEvent:event)
    } 

}

Then in your NodeB class:

然后在你的NodeB类中:

lazy var touchNode = TouchNode(withSize:self.scene!.size)

override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    addChild(touchNode)
    //do other stuff
} 
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    touchNode.removeFromParent()
    //do other stuff
} 

override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    touchNode.removeFromParent()
    //do other stuff
} 

#1


2  

When you hit your touchesBegan method, your touch is limited to the coordinate system of that node until the point it is ended. Moving onto another node will not change the coordinate system to the new node. If B is the only node that requires the touch, then you can add a child to cover the entire scene to ensure that B gets fired.

当您点击touchesBegan方法时,您的触摸仅限于该节点的坐标系,直到它结束。移动到另一个节点不会将坐标系更改为新节点。如果B是唯一需要触摸的节点,那么您可以添加一个子节点来覆盖整个场景,以确保B被触发。

class TouchNode : SKSpriteNode
{
    //if you need to override other inits do it here
    convenience init(withSize size:CGSize)
    {
       self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
       isUserInteractionEnabled = true

    }

    override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesBegan(touches:touches, withEvent:event)
    } 

    override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesMoved(touches:touches, withEvent:event)
    } 

    override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesEnded(touches:touches, withEvent:event)
    } 

    override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesCancelled(touches:touches, withEvent:event)
    } 

}

Then in your NodeB class:

然后在你的NodeB类中:

required init(coder aDecoder:NSCoder)
{
    super.init(coder:aDecoder)
    DispatchQueue.main.async{
        self.addChild(TouchNode(withSize:self.scene!.size))
    }
}
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    //do stuff
} 

Edit: Misread question, but leaving the answer in case somebody else needs to go from inside the node to outside.

编辑:误读问题,但留下答案以防其他人需要从节点内部转到外部。

Think about it, you want to touch nodeB outside of nodeB, this does not make sense. It is like me poking the air and you crying that I am poking you. But if you absolutely need to go outside of the bounds, then add a child node to the sprite when you touch it that extends beyond the node itself, and be sure to transfer the touch back up to the parent

想想看,你想在nodeB之外触摸nodeB,这没有意义。就像我在戳风,你哭着说我在戳你。但是如果你绝对需要超出边界,那么当你触摸它超出节点本身时,将一个子节点添加到精灵中,并确保将触摸传递回父节点

class TouchNode : SKSpriteNode
{
    //if you need to override other inits do it here
    convenience init(withSize size:CGSize)
    {
       self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
       isUserInteractionEnabled = true

    }

    override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesBegan(touches:touches, withEvent:event)
    } 

    override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesMoved(touches:touches, withEvent:event)
    } 

    override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesEnded(touches:touches, withEvent:event)
    } 

    override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
        parent!.touchesCancelled(touches:touches, withEvent:event)
    } 

}

Then in your NodeB class:

然后在你的NodeB类中:

lazy var touchNode = TouchNode(withSize:self.scene!.size)

override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    addChild(touchNode)
    //do other stuff
} 
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    touchNode.removeFromParent()
    //do other stuff
} 

override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) { 
    touchNode.removeFromParent()
    //do other stuff
}