ZachtheBoB
ZachtheBoB

Reputation: 400

touchesBegin not being called on Sprit Node

I have SpritNodes that are in my scene and I want a method to be called when I touch it. I have isUserInteractionEnabled set to true for my node, but touchesBegan still does not get called when I touch the nodes. (Note: I am using Swift 3.0)

Code:

    import SpriteKit

class MainScene: SKScene, SKPhysicsContactDelegate {

    var didStart = false
    var background = SKSpriteNode(imageNamed: "background")
    var backDrop = SKShapeNode()
    var emailNodes: [SKSpriteNode] = []

    let emailCatagory: UInt32 = 0x1 << 0
    let dropCatagory: UInt32 = 0x1 << 1

    override func sceneDidLoad() {
        startCountDown()
    }

    override func didMove(to view: SKView) {
        self.physicsWorld.contactDelegate = self

        background.position = CGPoint(x: frame.midX, y:frame.midY)
    }

    public func startCountDown(){
        var times = 4

        let countdownTimer = SKLabelNode()
        countdownTimer.text = "3"
        countdownTimer.position = CGPoint(x: frame.midX, y: frame.midY)
        countdownTimer.fontSize = 120.0
        countdownTimer.fontName = "Lao MN"
        countdownTimer.fontColor = UIColor.black()

        backDrop = SKShapeNode()
        backDrop = SKShapeNode(rectOf: CGSize(width: frame.width, height: 100))
        backDrop.position = CGPoint(x: frame.midX, y: 10)
        backDrop.physicsBody = SKPhysicsBody(rectangleOf: backDrop.frame.size)
        //backDrop.size = CGSize(width: 1000, height: 2)
        backDrop.physicsBody?.affectedByGravity = false
        backDrop.physicsBody?.usesPreciseCollisionDetection = true
        backDrop.name = "backDrop"
        backDrop.physicsBody?.collisionBitMask = 0
        backDrop.physicsBody?.categoryBitMask = dropCatagory

        addChild(countdownTimer)
        addChild(backDrop)
        //addChild(background)

        Timer.every(1.2.seconds) { (timer: Timer) in
            if(times<=0){
                timer.invalidate()
                countdownTimer.removeFromParent()
                self.didStart = true
                self.startDropping()
            }else{
                print("\(times)")
                times = times - 1
                countdownTimer.text = "\(times)"
            }
        }
    }

    func startDropping(){
        Timer.every(1.2.seconds) { (timer: Timer) in
            let which = Int(arc4random_uniform(2) + 1)
            let ee = self.getEmailNode(type: which)
            self.addChild(ee)
            ee.physicsBody?.applyImpulse(CGVector(dx: 0.0, dy: -5.0))
        }
    }

    func getEmailNode(type: Int) -> SKSpriteNode{
        var email = SKSpriteNode()
        if(type == 1){
            email = SKSpriteNode(imageNamed: "normal_email")
            email.name = "normal_email"
        }
        if(type == 2){
            email = SKSpriteNode(imageNamed: "classified_email")
            email.name = "classified_email"
        }
        email.setScale(3)
        email.position = CGPoint(x: getRandomColumn(), y: frame.height)
        email.physicsBody = SKPhysicsBody(rectangleOf: email.frame.size)
        email.physicsBody?.usesPreciseCollisionDetection = true
        email.physicsBody?.categoryBitMask = emailCatagory
        email.isUserInteractionEnabled = true
        email.physicsBody?.affectedByGravity = false
        email.physicsBody?.collisionBitMask = 0
        email.physicsBody?.contactTestBitMask = emailCatagory | dropCatagory
        emailNodes.append(email)
        return email
    }

    func getRandomColumn() -> CGFloat{
        let which = Int(arc4random_uniform(3) + 1)
        let gg = frame.size.width/3
        switch(which){
        case 1:
            return gg / 2
        case 2:
            return frame.midX
        case 3:
            return (gg * 3) - gg / 2
        default:
            return (gg * 3) + gg / 2
        }
    }

    func didBegin(_ contact: SKPhysicsContact) {
        if (contact.bodyA.categoryBitMask == dropCatagory) &&
            (contact.bodyB.categoryBitMask == emailCatagory) {
            let node = contact.bodyB.node as! SKSpriteNode
            node.removeFromParent()
            while emailNodes.contains(node) {
                if let itemToRemoveIndex = emailNodes.index(of: node) {
                    emailNodes.remove(at: itemToRemoveIndex)
                }
            }
        }
    }

    func doesContainNode(sk: SKSpriteNode) -> Bool {
        for it in emailNodes{
            if(it == sk){
                return true
            }
        }
        return false
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        enumerateChildNodes(withName: "//*", using:
            { (node, stop) -> Void in
                print("\(node.name)")
                print("\(node)")
                if((node.name?.contains("email")) != nil){
                    print("Touched!")
                }
        })
    }

}

Upvotes: 1

Views: 384

Answers (3)

ZachtheBoB
ZachtheBoB

Reputation: 400

I found a solution. I removed isUserInteractionEnabled and touchesBegan was still not being called. So I went through each of the properties of the "email" node and for some reason the following properties made it where touchesBegan would not be called.

email.physicsBody?.affectedByGravity = false
email.physicsBody?.collisionBitMask = 0

So I removed those and now touchesBegan is being properly called.

Upvotes: 1

Knight0fDragon
Knight0fDragon

Reputation: 16827

You do not want userInteractionEnabled set on any of your nodes, you want that only on the scene. Use userInteractionEnabled only when you are subclassing your node, this way you can use touchesBegan inside your subclassed file. What is happening is your touch is going into your node and being absorbed, which does nothing, and is being ignored by the scene since the node absorbed it.

Edit: Sorry @MarkBrownsword I did not see your comment, if you post it as an answer, I will upvote and delete my answer.

Upvotes: 1

Jozey
Jozey

Reputation: 1740

You should try the following in order to be able to get the user's position and know when the sprite has been touched. Add the following inside the touchesEnabled function.

for touch in touches {
    let userTouch = touch.locationInNode(self)
}

And then check if the sprite was touched by using:

node.containsPoint(userTouch)

See if that works. The way you have your code setup, you might need to nest the above function right after checking if it's nil. As for the userInteractionEnabled, I don't use it at all when using the above code.

Upvotes: 1

Related Questions