2

I've been researching, and definitely trying for a while, to find a way to activate a function when you tap a sprite. For example: If you tap the blue sprite, it activates blue(). Tap the red sprite, it activates red(). I have been searching for a while now and all the answers are either for older versions, or downright just don't work for me. Anybody have any ideas?

EDIT: Here is some of my code that I am using.

class GameScene: SKScene {

        var blue = SKSpriteNode()
        var red = SKSpriteNode()
        var green = SKSpriteNode()
        var help = SKLabelNode()
        var score = SKLabelNode()
        var points = 0
        var loseAmount = 1.0
        var firstAdvance = 0
        var loseTimer = Timer()

        override func didMove(to view: SKView) {

            self.physicsWorld.contactDelegate = self

            blue = self.childNode(withName: "blue") as! SKSpriteNode
            blue.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
            blue.name = "blue"
            blue.isUserInteractionEnabled = true

            red = self.childNode(withName: "red") as! SKSpriteNode
            red.position = CGPoint(x: self.frame.width / 2 + 100, y: self.frame.height / 2)
            red.name = "red"
            red.isUserInteractionEnabled = true

            green = self.childNode(withName: "green") as! SKSpriteNode
            green.position = CGPoint(x: self.frame.width / 2 - 100, y: self.frame.height / 2)
            green.name = "green"
            green.isUserInteractionEnabled = true

            help = self.childNode(withName: "help") as! SKLabelNode
            help.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 4 * 3)
            help.name = "help"
            help.isUserInteractionEnabled = false

            score = self.childNode(withName: "score") as! SKLabelNode
            score.position = CGPoint(x: self.frame.width / 2, y: self.frame.height - 40)
            score.name = "score"
            score.text = "\(points)"
            score.isUserInteractionEnabled = false

        }

        func randomMove() {
            blue.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))
            red.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))
            green.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))

        }

        func advance() {
            if (firstAdvance == 0) {
                firstAdvance = 1
                help.removeFromParent()
                points += 1
                playPointSound()
                randomMove()
                loseTimer = Timer.scheduledTimer(timeInterval: loseAmount, target: self, selector: #selector(GameScene.lose), userInfo: nil, repeats: true)

            } else if (firstAdvance == 1) {
                points += 1
                loseAmount -= 0.01
                playPointSound()
                self.loseTimer.invalidate()
                loseTimer = Timer.scheduledTimer(timeInterval: loseAmount, target: self, selector: #selector(GameScene.lose), userInfo: nil, repeats: true)

            }

        }

        func lose() {
            playLoseSound()
            let endSceneTemp = EndScene(fileNamed: "EndScene")
            self.scene?.view?.presentScene(endSceneTemp!, transition: SKTransition.crossFade(withDuration: 0.1))
        }

        func playPointSound() {
            let path = Bundle.main.path(forResource: "", ofType:nil)!
            let url = URL(fileURLWithPath: path)

            do {
                let sound = try AVAudioPlayer(contentsOf: url)
                pointSound = sound
                sound.play()
            } catch {
                // couldn't load file :(
            }
        }

        func playLoseSound() {
            let path = Bundle.main.path(forResource: "", ofType:nil)!
            let url = URL(fileURLWithPath: path)

            do {
                let sound = try AVAudioPlayer(contentsOf: url)
                loseSound = sound
                sound.play()
            } catch {
                // couldn't load file
            }
        }

        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            for touch in (touches) {
                let positionInScene = touch.location(in: self)
                let touchedNode = self.atPoint(positionInScene)
                if let name = touchedNode.name {
                    if name == "blue" {
                        advance()
                    }
                    if name == "red" || name == "green"{
                        lose()
                    }
                }
            }
        }

        override func update(_ currentTime: TimeInterval) {

        }
    }
Mina
  • 2,167
  • 2
  • 25
  • 32
DJDJ
  • 23
  • 4
  • 1
    This depends a lot on how you create the sprite, and how you add it to the scene, and what else is in the scene. Can you provide any of this information? – Confused Dec 23 '16 at 05:11
  • @Confused My sprites are created through a .sks file. There is not much in the scene except a red node, a blue node, and a green node. Hope this helps. – DJDJ Dec 23 '16 at 15:46

2 Answers2

2

you just need to assign a name for your sprites:

let redSpriteNode = SKSpriteNode(imageNamed: "red") // add sprite by code
//let redSpriteNode = self.childNode(withName: "red") as! SKSpriteNode // for adding from .sks file
redSpriteNode.name = "red"
let blueSpriteNode = SKSpriteNode(imageNamed: "blue")
redSpriteNode.name = "blue"

and in touches began method activate the desire function.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches) {
            let positionInScene = touch.location(in: self)
            let touchedNode = self.atPoint(positionInScene)
            if let name = touchedNode.name {
                if name == "red" {
                   red()
                }
                if name == "blue" {
                   blue()
                }
            }
        }
    }

you can find all nodes with the same name like this: (reference)

self.enumerateChildNodes(withName: "red") {_,_ in
   print(count)
   count = count + 1
}
Community
  • 1
  • 1
Mina
  • 2,167
  • 2
  • 25
  • 32
  • That doesn't seem to be working for me for some reason. I am using nodes from an .sks file, yes. However, this still does not work for me. – DJDJ Dec 23 '16 at 15:45
  • @DJDJ did you assign a name to each node using the .sks editor? – 0x141E Dec 23 '16 at 20:22
  • As @0x141E said you have to set name for your nodes – Mina Dec 23 '16 at 20:28
  • @0x141E @Mina Yes I have set a name for all of my sprites by using `blue = self.childNode(withName: "blue") as! SKSpriteNode` and `blue.name = "blue"` – DJDJ Dec 23 '16 at 22:25
  • add some code to your question please, it may be helpful for us to find the problem. – Mina Dec 24 '16 at 04:59
  • I do not currently have my code with me, but once I do, I will add some more. – DJDJ Dec 24 '16 at 17:42
  • @Mina I edited my question and added most of my code. – DJDJ Dec 25 '16 at 19:46
  • remove `.isUserInteractionEnabled = true` from your nodes, everything will work fine. – Mina Dec 26 '16 at 06:18
  • @Mina Yes, thank you so much! However, this is only working once. Is there a way to somewhat... "reset the blue touch." What is happening is it is only letting me touch the blue once, and then it doesn't work for the rest of the round. The red and green are fine, until I of course touch them. Have any ideas? – DJDJ Dec 26 '16 at 15:19
  • @Mina Nevermind, just had to add a randomMove() to the advance() function. Thank you so much, you really did fix my game! :) – DJDJ Dec 26 '16 at 15:21
0

What worked best for me was to add a UITapGestureRecognizer to the SKView and then handle tap gestures on that within the scene.

When the taps are made you can get the location in view and then convert that to the location in the scene. With that you can look for the nodeAtPoint: for the tap location.

When you have that node you then check its name and perform an action on that SKSpriteNode if its name is one you want to do something on a tap.

While you can do this with overriding touchesBegan:, touchesMoved: and such you save a little effort when you are attempting to capture more complex touches such as a pinch as you don't need to figure out what is a tap vs. long press vs. pinch first.

Mark Reid
  • 2,611
  • 3
  • 23
  • 45