Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HitTest for SKSpriteNode

This is my problem:

I work with SpriteKit and I want to ignore touch event when it occurs in some rectangle (prevent calling touchesBegan). The way how I would like to do it is something like "overriding the hitTestWithEvent of UIView". But I can't find any similar method for SKSpriteNode that could ignore event and prevent calling touchesBegan.

Sure

  • I could set isUserInteractionEnabled to false but it disables the whole sprite not just a part.
  • I could check location of touch in touchesBegan method, but this is to late - others sprites beneath at the same position will not receive this event anymore.
  • I also tried to use SKCropNode, but it just prevent displaying the sprite and events are handled even on the invisible area.

Does anybody have idea how to prevent part of sprite from handling an event?

like image 266
ukaszm Avatar asked Nov 09 '22 03:11

ukaszm


1 Answers

The open func nodes(at p: CGPoint) -> [SKNode] can be useful to detect which nodes you have touched to a point. After that, you can exclude the CGRect zone for each node you want..

import SpriteKit
class GameScene: SKScene {
    var warningZone = CGRect(x: -80, y: -60, width: 100, height: 100)
    override func didMove(to view: SKView) {
        let nodeRed = SKSpriteNode.init(color: .red, size: CGSize(width:300,height:200))
        nodeRed.name = "nodeRed"
        addChild(nodeRed)
        nodeRed.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
        let nodeBlue = SKSpriteNode.init(color: .blue, size: CGSize(width:300,height:200))
        nodeBlue.name = "nodeBlue"
        addChild(nodeBlue)
        nodeBlue.position = CGPoint(x:self.frame.midX+100,y:self.frame.midY+20)
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            let nodesTouched = self.nodes(at: location)
            for node in nodesTouched {
                guard let n = node.name else { return }
                print("Node touched: \(node.name) at point:\(location)")
                switch n {
                case "nodeRed":
                    // do your exclusions for the nodeRed
                    print("\(node.frame)")
                    if !warningZone.contains(location) {
                        print("you have touch a safe red zone")
                    }
                case "nodeBlue":
                    // do your exclusions for the nodeBlue
                    print("\(node.frame)")
                default:
                    break
                }
            }
        }
    }
}

Output (I've draw the warningZone with a white rectangle only to show you where is it..): enter image description here

like image 186
Alessandro Ornano Avatar answered Nov 14 '22 22:11

Alessandro Ornano